哈夫曼編碼測試

哈夫曼編碼測試

測試要求

設有字符集: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)把實驗結果截圖上傳到雲班課node

測試完成過程

讀取文件:

  • 對於讀取文件,以前是通過了簡單的學習,可是還有不少的知識沒有掌握。統計字符的時候,學習了一下,採用了下面的寫法
//讀取文件中出現的字符,並記錄出現次數
        File file = new File("C:\\Users\\12257\\IdeaProjects\\20172310qx\\src\\Huffman\\text");

        if (!file.exists()) {
            throw new Exception("文件不存在");
        }

        BufferedReader fin = new BufferedReader(new FileReader(file));
        String line;

        //map儲存數據的形式是一個key和一個value對應
        Map<Character, Integer> counter = new HashMap<Character, Integer>();

        int total=0;

        //讀取一個文本行
        while ((line = fin.readLine()) != null)
        {
            int len = line.length();
            for (int i = 0; i < len; i++)
            {
                char c = line.charAt(i);
                if (( (c >= 'a' && c <= 'z'&& c == ' ')))
                {
                    continue;
                }

                // 若是此映射包含指定鍵的映射關係,則返回 true
                if (counter.containsKey(c))
                {
                    counter.put(c, counter.get(c) + 1);
                }
                else
                {
                    counter.put(c, 1);
                }
            }
        }

        fin.close();//文件讀取結束

        //經過Map.keySet遍歷key和value:
        Iterator<Character> pl = counter.keySet().iterator();

        int a = 0;
        while (pl.hasNext())
        {
            char key = pl.next();
            int count = counter.get(key);
//            System.out.println(key + " --- " + count);
            a++;
        }
  • 其中用了一些JavaAPI中的方法:

構造哈夫曼樹

  • 哈夫曼樹被稱爲最優樹,有着二叉樹的全部性質,可是要帶上權重和記住左邊的編碼爲「0」,右邊的編碼爲「1」,因此重寫了哈弗曼樹的節點類
private T data;//數據

        public T getData() {
            return data;
        }

        public void setData(T data) {
            this.data = data;
        }

        protected double weight;//權重

        protected Node<T> leftChild;
        protected Node<T> rightChild;

        public String codeNumber;

        public Node(T data , double weight)

        {
            this.data = data;
            this.weight = weight;
            this.codeNumber = "";
        }

        public String getCodeNumber() {
            return codeNumber;
        }

        public void setCodeNumber(String codeNumber) {
            this.codeNumber = codeNumber;
        }

        public double getWeight() {
            return weight;
        }

        public void setWeight(double weight) {
            this.weight = weight;
        }
        public String toString()
        {
            return "Node[data=" + data
                    + ", weight=" + weight + ",codeNumber = "+codeNumber+"]";
        }
    }
  • 基本思路:1)如今給定的n個有權值的元素,要構成一棵哈弗曼樹,首先將這些元素按照權值,從小到大排序
    2)而後在其中選擇兩個權值最小元素構成一棵二叉樹的左右孩子,計算兩個元素的權值之和,放入該二叉樹的根節點中,
    3)再從原對列中刪除被選中的那兩個元素,而且把構成的新的元素加到對列中,從新排序
    4)重複2 ,3 操做,直到構成一棵完整的二叉樹,就是哈夫曼樹。
    如圖:

public static Node createTree(List<Node> nodes) {

            // 只要nodes數組中還有2個以上的節點
            while (nodes.size() > 1)
            {
                quickSort(nodes);

                //獲取權值最小的兩個節點
                Node left = nodes.get(nodes.size()-1);
                left.setCodeNumber(0+"");
                Node right = nodes.get(nodes.size()-2);
                right.setCodeNumber(1+"");

                //生成新節點,新節點的權值爲兩個子節點的權值之和
                Node parent = new Node(null, left.weight + right.weight);

                //讓新節點做爲兩個權值最小節點的父節點
                parent.leftChild = left;
                parent.rightChild = right;

                //刪除權值最小的兩個節點
                nodes.remove(nodes.size()-1);
                nodes.remove(nodes.size()-1);

                //將新節點加入到集合中
                nodes.add(parent);
            }
            return nodes.get(0);
        }

編碼和解碼過程

如今已經對每一個字符都進行了對應的編碼,只要一一對應就能夠相應的編碼解碼。git

double num2 = 0;
        for (int i = 0; i < list2.size(); i++) {
            num2 += list2.get(i).getWeight();
        }

        for (int i = 0; i < list3.size(); i++) {
            System.out.println("字符爲:"+list3.get(i) + "機率爲:" + list2.get(i).getWeight() / num2 + "  ");
        }

        System.out.println();
        String temp2 = "", temp3 = "";

        for (int i = 0; i < list4.size(); i++)
        {
            System.out.println(list3.get(i) + "的編碼爲" + list4.get(i) + " ");
        }

        System.out.println();
List<String> list5 = new ArrayList<String>();
        System.out.println();

        for (int i = 0; i < result.length(); i++)
        {
            for (int j = 0; j < list3.size(); j++)
            {
                if (result.charAt(i) == list3.get(j).charAt(0))
                    result1 += list4.get(j);
            }
        }

        System.out.println("編碼後爲:" + result1);

測試結果



代碼連接

相關文章
相關標籤/搜索