哈夫曼


學號 20182334 《數據結構與面向對象程序設計》哈弗曼實驗

課程:《程序設計與數據結構》

班級: 1823

姓名: 姬旭

學號:20182334

實驗教師:王志強

實驗日期:2019年11月22日

必修/選修: 必修

1.實驗內容

什么是哈夫曼樹呢?

設有字符集:S={a,b,c,d,e,f,g,h,i,j,k,l,m,n.o.p.q,r,s,t,u,v,w,x,y,z}。

給定一個包含26個英文字母的文件,統計每個字符出現的概率,根據計算的概率構造一顆哈夫曼樹。
並完成對英文文件的編碼和解碼。
要求:

  • (1)准備一個包含26個英文字母的英文文件(可以不包含標點符號等),統計各個字符的概率

  • (2)構造哈夫曼樹

  • (3)對英文文件進行編碼,輸出一個編碼后的文件

  • (4)對編碼文件進行解碼,輸出一個解碼后的文件

  • (5)撰寫博客記錄實驗的設計和實現過程,並將源代碼傳到碼雲

  • (6)把實驗結果截圖上傳到雲班課

2. 實驗過程及結果

例如:頻率表 A:60, B:45, C:13 D:69 E:14 F:5 G:3

第一步:找出字符中最小的兩個,小的在左邊,大的在右邊,組成二叉樹。在頻率表中刪除此次找到的兩個數,並加入此次最小兩個數的頻率和。

F和G最小,因此如圖,從字符串頻率計數中刪除F與G,並返回G與F的和 8給頻率表

重復第一步:


頻率表 A:60, B:45, C:13 D:69 E:14 FG:8

最小的是 FG:8與C:13,因此如圖,並返回FGC的和:21給頻率表。


重復第一步:


頻率表 A:60 B: 45 D: 69 E: 14 FGC: 21

如圖


重復第一步


頻率表 A:60 B: 45 D: 69 FGCE: 35


重復第一步


頻率表 A:60 D: 69 FGCEB: 80


重復第一步


頻率表 AD:129 FGCEB: 80

添加 0 和 1,規則左0 右1

頻率表 A:60, B:45, C:13 D:69 E:14 F:5 G:3

每個 字符 的 二進制編碼 為(從根節點 數到對應的葉子節點,路徑上的值拼接起來就是葉子節點字母的應該的編碼)

A:10

B:01

C:0011

D:11

E:000

F:00101

G:00100

來源於哈夫曼樹原理,及構造方法


1.創建哈夫曼樹:(函數參數為整型數組)

  • (1)引入哈夫曼樹指針數組並申請空間,為每棵哈夫曼樹復制,將其左右節點賦值為NULL。

  • (2)將(n-1)棵哈夫曼樹合並:

    a.引入兩個整形變量始終代表最小和次小的下標

    b.比較權值,使兩個下標成為最小的兩個權值的下標

    c.合並一次,並將最小下標的哈夫曼樹賦值為新的哈夫曼樹,次小下表的哈夫曼樹賦值為空。

2.輸出哈夫曼樹:根節點不為空,輸出權重,若左右子樹不為空,依次輸出“(”, 左子樹,“,”,右子樹,“)”

3.遞歸進行哈夫曼編碼:由於哈夫曼樹的特點是所有的原始樹都為葉子節點,故可以用這方法來進行編碼。

4.哈夫曼解碼:while(已解碼長度<字符串長度){找到某一葉子節點並打印}

1、創造樹:

public static HuffNode createTree(List<HuffNode> nodes) {
       //先獲取兩個最小的結點,再存入新的節點。
        while (nodes.size() > 1) {
            //進行從大到小的排序
            Collections.sort(nodes);
            //獲取
            HuffNode left = nodes.get(nodes.size() - 1);
            HuffNode right = nodes.get(nodes.size() - 2);
            //求和
            HuffNode parent = new HuffNode('無', left.getWeight() + right.getWeight());
            //讓新節點作為兩個權值最小節點的父節點
            parent.setLeft(left);
            left.setCodenumber("0");
            parent.setRight(right);
            right.setCodenumber("1");
            //刪除
            nodes.remove(left);
            nodes.remove(right);
            //重新寫入
            nodes.add(parent);
        }
        return nodes.get(0);
    }

2、找

public static  List<HuffNode> breadthFirstTraversal(HuffNode root) {
        List<HuffNode> list = new ArrayList<HuffNode>();
        Queue<HuffNode> queue = new ArrayDeque<HuffNode>();

        //將根元素加入“隊列
        if (root != null) {
            queue.offer(root);
            root.getLeft().setCodenumber(root.getCodenumber() + "0");
            root.getRight().setCodenumber(root.getCodenumber() + "1");
        }

        while (!queue.isEmpty()) {
            //將該隊列的“隊尾”元素加入到list中
            list.add(queue.peek());
            HuffNode node = queue.poll();

            //如果左子節點不為null,將它加入到隊列
            if (node.getLeft() != null) {
                queue.offer(node.getLeft());
                node.getLeft().setCodenumber(node.getCodenumber() + "0");
            }
            //如果右子節點不為null,將它加入到隊列
            if (node.getRight() != null) {
                queue.offer(node.getRight());
                node.getRight().setCodenumber(node.getCodenumber() + "1");
            }
        }
        return list;
    }

3、做測試

public class HuffmanTest {
    public static void main(String[] args) throws IOException {
        //把字符集從文件中讀出來,並保存在一個數組characters里面
        File file = new File("D:\\Huffman.txt");
        if(!file.exists()){
            file.createNewFile();
        }

        Reader reader = new FileReader(file);
        BufferedReader bufferedReader = new BufferedReader(reader);
        String temp = bufferedReader.readLine();

        char characters[] = new char[temp.length()];
        for (int i = 0; i < temp.length(); i++) {
            characters[i] = temp.charAt(i);
        }
        System.out.println("原字符集為:" + Arrays.toString(characters));

        //計算每一個字符出現的頻率。並把出現的概率存在另一個數組中
        double frequency[] = new double[27];
        int numbers = 0;
        for (int i = 0; i < characters.length; i++) {
            if (characters[i] == ' ') {
                numbers++;
            }
            frequency[26] = (float) numbers / characters.length;
        }

        for (int j = 97; j <= 122; j++) {
            int number = 0;//給字母計數
            for (int m = 0; m < characters.length; m++) {
                if (characters[m] == (char) j) {
                    number++;
                }
                frequency[j - 97] = (float) number / characters.length;
            }
        }

        System.out.println("\n每一個字符對應的概率為(26字母+空格)" + "\n" + Arrays.toString(frequency));
        List<HuffNode> nodes = new ArrayList<>();
        for (int o = 97; o <= 122; o++) {
            nodes.add(new HuffNode((char) o, frequency[o - 97]));
        }
        nodes.add(new HuffNode(' ', frequency[26]));

        HuffNode root = HuffmanTree.createTree(nodes);
        String result1 = "";
        List<HuffNode> temp1 = breadthFirstTraversal(root);

        for (int i = 0; i < characters.length; i++) {
            for (int j = 0; j < temp1.size(); j++) {

                if (characters[i] == temp1.get(j).getData()) {
                    result1 += temp1.get(j).getCodenumber();
                }
            }
        }
        System.out.println("\n對文件進行編碼后的結果為:");
        System.out.println(result1);
        File file2 = new File("D:\\enHuffman.txt");
        Writer writer = new FileWriter(file2);
        writer.write(result1);
        writer.close();

//將所有具有字符的葉子節點重新保存在一個newlist里面
        List<String> newlist = new ArrayList<>();
        for(int m=0;m < temp1.size();m++)
        {
            if(temp1.get(m).getData()!='無')
                newlist.add(String.valueOf(temp1.get(m).getData()));
        }
        System.out.println("\n字符:"+newlist);

        List<String> newlist1 = new ArrayList<>();
        for(int m=0;m < temp1.size();m++)
        {
            if(temp1.get(m).getData()!='無')
                newlist1.add(String.valueOf(temp1.get(m).getCodenumber()));
        }
        System.out.println("\n對應編碼:"+newlist1);
        FileReader fileReader = new FileReader("D:\\enHuffman.txt");
        BufferedReader bufferedReader1 = new BufferedReader(fileReader);
        String secretline = bufferedReader1.readLine();

        List<String> secretText = new ArrayList<String>();
        for (int i = 0; i < secretline.length(); i++) {
            secretText.add(secretline.charAt(i) + "");
        }

        //解密
        String result2 = "";
        String current="";// linshizhi
        while(secretText.size()>0) {
            current = current + "" + secretText.get(0);
            secretText.remove(0);
            for (int p = 0; p < newlist1.size(); p++) {
                if (current.equals(newlist1.get(p))) {
                    result2 = result2 + "" + newlist.get(p);
                    current="";
                }

            }
        }
//最后輸出
        System.out.println("\n解碼后的結果:"+result2);
        File file3 = new File("D:\\deHuffman.txt");
        Writer writer1 = new FileWriter(file3);
        writer1.write(result2);
        writer.close();
    }
}



其他(感悟、思考等)

隨着期末的到來,各科學習任務都加劇了起來,所有科目都在復習,但是java依然占據很多時間,大作業布置下來,大家都想把它做好,所以有時候里面會產生很多誤會,這就很不應該了,但細想也不能避免,畢竟大家的好勝心還是很強的,都在用自己的方式讓自己的APP變得更完美,成為最出色的那一個,我們也不例外,所以對於這個實踐上的心就比較少,所以做出來的結果也比較一般。

參考資料

《Java程序設計與數據結構教程(第二版)》

《Java程序設計與數據結構教程(第二版)》學習指導
-  ...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM