java_實現Haffman樹及其編碼與解碼
哈夫曼樹的建立與哈夫曼編碼的實現
目的和要求:
(1)正確定義哈夫曼樹結點
(2)掌握哈夫曼樹的建立方法
(3)掌握根據哈夫曼樹進行編碼的方法
(4)根據哈夫曼編碼解決實際問題
實驗原理及內容:
(1)定義哈夫曼樹結點
(2)哈夫曼樹的建立方法
(3)根據哈夫曼樹進行編碼
實驗步驟:
(1)定義哈夫曼樹結點
(2)哈夫曼樹的建立方法
(3)根據哈夫曼樹進行編碼
實驗過程:
(1)哈夫曼樹結點定義
public class HNode { private int weight; //結點權值 private int lchild; //左孩子結點 private int rchild; //右孩子結點 private int parent; //父結點 private String name; //結點資料,存放字元名稱 private String code;//存放葉子結點的字元編碼 //構造器 public HNode(String name, int w){ this.weight = w; this.name = name; this.lchild = -1; this.rchild = -1; this.parent = -1; this.code = ""; } public HNode(){ this(null,0); } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public int getLchild() { return lchild; } public void setLchild(int lchild) { this.lchild = lchild; } public int getRchild() { return rchild; } public void setRchild(int rchild) { this.rchild = rchild; } public int getParent() { return parent; } public void setParent(int parent) { this.parent = parent; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
(2)哈夫曼樹的定義、建立及哈夫曼編碼、解碼
import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; public class HuffmanTree { private HNode[] data; // 結點陣列 private int leafNum; // 葉子結點數目 // 構造哈夫曼樹 public void create() { Scanner sc = new Scanner(System.in); System.out.println("請輸入要傳輸的報文:"); String str = sc.nextLine().toLowerCase(); str = str.replace(" ", ""); //去掉空格 int[] c = new int[26]; for (int i = 0; i < str.length(); i++) { // 統計各字元出現的頻率 c[str.charAt(i) - 'a']++; } int cnt = 0; for (int i = 0; i < 26; i++) { // 統計報文中字元的數量 if (c[i] > 0) cnt++; } this.leafNum = cnt; data = new HNode[this.leafNum * 2 - 1]; for (int i = 0; i < 2 * leafNum - 1; i++) data[i] = new HNode(); cnt = 0; for (int i = 0; i < 26; i++) { // 用字元建立葉子結點 if (c[i] > 0) { data[cnt].setName((char) (i + 'a') + ""); data[cnt++].setWeight(c[i]); } } int m1, m2, x1, x2; // 處理n個葉子結點,建立哈夫曼樹 for (int i = 0; i < this.leafNum - 1; ++i) { m1 = m2 = Integer.MAX_VALUE; // m1:最小權值,m2:次小權值 x1 = x2 = 0; // x1:權值最小位置,x2:權值次小位置 // 在全部結點中找權值最小的兩個結點 for (int j = 0; j < this.leafNum + i; ++j) { if ((data[j].getWeight() < m1) && (data[j].getParent() == -1)) { m2 = m1; x2 = x1; m1 = data[j].getWeight(); x1 = j; } else if ((data[j].getWeight() < m2) && (data[j].getParent() == -1)) { m2 = data[j].getWeight(); x2 = j; } } // 用兩個權值最小點構造一個新的中間結點 data[this.leafNum + i].setWeight(data[x1].getWeight() + data[x2].getWeight()); data[this.leafNum + i].setLchild(x1); data[this.leafNum + i].setRchild(x2); // 修改權值最小的兩個結點的父結點指向 data[x1].setParent(this.leafNum + i); data[x2].setParent(this.leafNum + i); } } //輸出哈夫曼樹結構 public void print() { System.out.println("位置\t字元\t權值\t父結點\t左孩子結點\t右孩子結點"); for (int i = 0; i < 2 * leafNum - 1; i++) { System.out.printf("%d\t%s\t%d\t%d\t%d\t%d\r\n", i, data[i].getName(), data[i].getWeight(), data[i].getParent(), data[i].getLchild(), data[i].getRchild()); } } // 前序遍歷,輸出所有葉子結點的編碼,並計算總的報文編碼長度 private int preorder(HNode root,String code) { int sum = 0; if (root != null) { root.setCode(code); if(isLeaf(root)){ //葉子結點,輸出編碼,並計算長度 System.out.println(root.getName() + ":" + root.getCode()); return root.getWeight()*root.getCode().length(); } if(root.getLchild()!=-1){ //左子樹,編碼為0,並統計左子樹葉子結點的編碼長度 sum +=preorder(data[root.getLchild()],code+"0"); } if(root.getRchild()!=-1){ //右子樹,編碼為1,並統計右子樹所有葉子結點的編碼長度 sum +=preorder(data[root.getRchild()],code+"1"); } } return sum; } //層序遍歷,求報文傳輸的總長度 private void levelOrder(){ //根結點的位置 int root = 2*leafNum-2; // 根結點為空 if (root == -1) { return; } // 設定一個佇列儲存層序遍歷的結點 Queue<HNode> q = new LinkedList<HNode>(); // 根結點入隊 q.add(data[root]); int sum = 0; String code = ""; // 佇列非空,結點沒有處理完 while (!q.isEmpty()) { // 結點出隊 HNode tmp = q.poll(); code = tmp.getCode(); // 如果是葉子結點,則計算編碼長度 if(isLeaf(tmp)){ sum +=tmp.getWeight()*tmp.getCode().length(); } // 將當前結點的左孩子結點入隊 if (tmp.getLchild() != -1) { q.add(data[tmp.getLchild()]); data[tmp.getLchild()].setCode(code+"0"); } if (tmp.getRchild() != -1) { // 將當前結點的右孩子結點入隊 q.add(data[tmp.getRchild()]); data[tmp.getRchild()].setCode(code+"1"); } } System.out.println("總的報文長度為:"+sum); } //採用層序遍歷,進行報文解碼 public String decodes(String codes){ //根結點的位置 int root = 2*leafNum-2; // 根結點為空 if (root == -1) { return ""; } // 設定一個佇列儲存層序遍歷的結點 Queue<HNode> q = new LinkedList<HNode>(); // 根結點入隊 q.add(data[root]); int i = 0; String str = ""; // 佇列非空,結點沒有處理完 while (!q.isEmpty()) { // 結點出隊 HNode tmp = q.poll(); if(!codes.startsWith(tmp.getCode())) continue; // 如果是葉子結點,則計算編碼長度 if(isLeaf(tmp)){ str = str + tmp.getName(); codes = codes.substring(tmp.getCode().length()); if(codes.length()>0){ //如果存在多個報文字元,則繼續重新解碼 while(!q.isEmpty()) q.poll(); q.add(data[root]); continue; } } // 將當前結點的左孩子結點入隊 if (tmp.getLchild() != -1) { q.add(data[tmp.getLchild()]); } if (tmp.getRchild() != -1) { // 將當前結點的右孩子結點入隊 q.add(data[tmp.getRchild()]); } } return str; } // 層次遍歷 public void traverse() { //根結點的位置 int root = 2*leafNum-2; // 根結點為空 if (root == -1) { return; } int sum = preorder(data[root],""); System.out.println("所有報文長度為(位):"+sum); } // 判斷是否是葉子結點 public boolean isLeaf(HNode p) { return ((p != null) && (p.getLchild() == -1) && (p.getRchild() == -1)); } }
(3)哈夫曼樹測試
import java.util.Scanner; public class TestHuffmanTree { // 測試哈夫曼樹 public static void main(String[] args) { HuffmanTree ht = new HuffmanTree(); ht.create(); //建立哈夫曼樹 //ht.print(); //輸出哈夫曼樹結構 ht.traverse(); //輸出所有字元編碼 String op = ""; do{ System.out.println("請輸入一個報文編碼進行解碼:"); Scanner sc = new Scanner(System.in); String codes = sc.nextLine(); String decodes = ht.decodes(codes); //報文解碼 if(decodes.length()==0){ System.out.println("解碼出錯!"); }else{ System.out.println("對應的報文為:"+decodes); } System.out.println("按X鍵退出,其他鍵繼續"); op = sc.nextLine(); }while(!op.toLowerCase().equals("x")); System.out.println("程式退出"); } }
相關推薦
java_實現Haffman樹及其編碼與解碼
哈夫曼樹的建立與哈夫曼編碼的實現 目的和要求: (1)正確定義哈夫曼樹結點 (2)掌握哈夫曼樹的建立方法 (3)掌握根據哈夫曼樹進行編碼的方法 (4)根據哈夫曼編碼解決實際問題 實驗原理及內容: (1)定義哈夫曼樹結點 (2)哈夫曼樹的建立方法 (3)根據哈
哈夫曼樹的編碼與解碼
#include<stdio.h> #include<stdlib.h> #include<iostream> #include<string> using namespace std; #define MAXSIZE 30
DS二叉樹——Huffman編碼與解碼
題目描述 1、問題描述 給定n個字元及其對應的權值,構造Huffman樹,並進行huffman編碼和譯(解)碼。 構造Huffman樹時,要求左子樹根的權值小於、等於右子樹根的權值。 進行Huffman編碼時,假定Huffman樹的左分支上編碼為‘0’,右
20172303 2018-2019-1《程式設計與資料結構》哈夫曼樹編碼與解碼
20172303 2018-2019-1《程式設計與資料結構》哈夫曼樹編碼與解碼 哈夫曼樹簡介 定義:給定n個權值作為n個葉子結點,構造一棵二叉樹,若帶權路徑長度達到最小,稱這樣的二叉樹為最優二叉樹,也稱為哈夫曼樹(Huffman Tree)。哈夫曼樹是帶權路徑長度最短的樹,權值較大的結點離根較近。
20172303 2018-2019-1《程序設計與數據結構》哈夫曼樹編碼與解碼
exce eat temp 基礎 第一個 最小 charat 轉換 except 20172303 2018-2019-1《程序設計與數據結構》哈夫曼樹編碼與解碼 哈夫曼樹簡介 定義:給定n個權值作為n個葉子結點,構造一棵二叉樹,若帶權路徑長度達到最小,稱這樣的二叉樹為最
Huffman(哈夫曼)樹編碼與解碼程式(全)
關於Huffman樹構建與編碼的原理,很多書上有介紹,我在這裡就只給出相應的程式,包括樹的構建,2種編碼方法,譯碼(這部分是我自己獨立寫的,肯定有不當之處,歡迎回帖指正)等,裡面註釋也很清晰,費了很大勁,希望對大家有幫助。 <span style="font-siz
用python實現base64編碼與解碼
用到了python裡的base64模組 用法: 編碼: 1 import base64 2 a = 'HC'.decode() #將‘HC’轉為二進位制 3 b = base64.b64encode(a) #將a轉為base64編碼 4 b.decode() #從二進位制轉回 5 6 base6
【APACHE MINA2.0開發之二】自定義實現SERVER/CLIENT端的編解碼工廠(自定義編碼與解碼器)!
在上一篇博文中已經簡單介紹過“過濾器”的概念,那麼在Mina 中的協議編解碼器通過過濾器 ProtocolCodecFilter 構造,這個過濾器的構造方法需 要一個 ProtocolCodecFactory,這從前面註冊 TextLineCodecFactory 的程式碼就可以看出來。 Protoc
.net C#實現Base64編碼與解碼
一、編碼規則 Base64編碼的思想是是採用64個基本的ASCII碼字元對資料進行重新編碼。它將需要編碼的資料拆分成位元組陣列。以3個位元組為一組。按順序排列24 位資料,再把這24位資料分成4組,即每組6位。再在每組的的最高位前補兩個0湊足一個位元組。這樣就把一
C#實現Base64編碼與解碼 自定義
/// <summary> /// Base64編碼類。 /// 將byte[]型別轉換成Base64編碼的string型別。 ///</summary> public class Base64Encoder { byte[] source; int length, length2;
編碼與解碼
文本 也有 文件的 一位 pri 一行 word 終端 二進制位 編碼:真實字符與二進制串的對應關系,真實字符→二進制串 解碼:二進制串與真實字符的對應關系,二進制串→真實字符 首先,明確一點,計算機中存儲的信息都是二進制的 編碼/解碼本質上是一種映射(對應關系),比如
從Python的角度來看編碼與解碼
異常 字符 default 疑問 習慣 中文字符集 nbsp prompt ans 導語: Python2和Python3中,因為默認字符集的不同而造成的麻煩,簡直是程序員的夢魘!要徹底告別這個麻煩,就需要從本質上來理解編碼和解碼。 為什麽要有編碼? 對於不會英文的中國
Java-IO流之轉換流的使用和編碼與解碼原理
鍵盤輸入 tostring delet 特點 rgb utf8 equals pri 數據 一、理論: 1、字符流和字節流區別是什麽? 字符流=字節流+編碼集,在實際讀取的時候其實字符流還是按照字節來讀取,但是會更具編碼集進行查找編碼集字典解析相應的字節,使得一次讀取出一個
html 編碼與解碼
fine 動態創建 innertext 編碼 document 元素 tco innerhtml content var HtmlUtil = { /*1.用瀏覽器內部轉換器實現html轉碼*/ htmlEncode:function (html){
JavaScript進行UTF-8編碼與解碼
str 前端 轉載 clas utf-8 處理 序列 一個 ket JavaScript本身可通過charCodeAt方法得到一個字符的Unicode編碼,並通過fromCharCode方法將Unicode編碼轉換成對應字符。 但charCodeAt方法得到的應該是一個16
Python3.X Socket 一個編碼與解碼的坑
time() 解碼 oss 數據 tex href real byte 錯誤 最近在看《Python核心編程》第三版 講述網絡編程Socket的知識,在練習中采用Python 3 的代碼中遇到一個與編碼解碼有關的坑,本文將給予詳細的介紹。 軟件環境 Python: 3.6.
08_Python編碼與解碼
文字 新的 方式 服務 nbsp 存儲器 san har hang 一、編碼的由來 因為計算機只能處理010101二進制數據,如果要處理文本,圖像,視頻等,需要我們把數據轉換成01010二進制格式才能被計算機處理 最先出現的是ASCII,用8位一個字節來表示,成為單字節碼,
python字符串格式和編碼與解碼問題
連接 hello 列表 enc nbsp utf 而不是 取數據 無符號 1 %c 轉換成字符(ASCII碼值,長度為一的字符串) 2 3 %r 有線使用repr()函數進行字符串轉換 4 5 %s 有線使用str()函數進行字符串轉換 6
Python3中字符串的編碼與解碼以及編碼之間轉換(decode、encode)
python3 encode 由於 表示 nic code .... 以及 mage 一、編碼 二、編碼與解碼 Python3中對py文件的默認編碼是urf-8。但是字符串的編碼是Unicode。 由於Unicode采用32位4個字節來表示一個字符,存儲和傳輸太浪費資
【轉】python基礎-編碼與解碼
什麽 浪費 2.x sys 拼接 aced tro lte bytes 【轉自:https://www.cnblogs.com/OldJack/p/6658779.html】 一、什麽是編碼 編碼是指信息從一種形式或格式轉換為另一種形式或格式的過程。 在計算機中,編碼,簡而