Huffman的应用_Huffman编码

时间:2020-12-21 21:16:38
  1 //最优二叉树
2 #include <iostream>
3 #include <iomanip>
4 using namespace std;
5
6 //定义结点类型
7 //【weight | lchid | rchild | parent】
8 //为了判定一个结点是否已加入到要建立的哈夫曼树中
9 //可通过parent域的值来确定.
10 //初始时parent = -1,当结点加入到树中时,该结点parent的值
11 //为其父亲结点在数组Huffman中的序号.
12 template<typename T>
13 struct HuffNode {
14 T weight; //权值
15 int parent; //指向父节点的指针域(结点元素的下标)
16 int lch; //左指针域
17 int rch; //右指针域
18 };
19
20 //哈夫曼树的构造算法
21 template<typename T>
22 HuffNode<T> *HuffmanTree(int n, const T& sign) //生成最优二叉树
23 {
24 const int MAX_VALUE = 100000;
25 int i, j, min1, min2, x1, x2; //min1为最小值, min2为次小值, x1位最小值下标, x2位次小值下标
26 HuffNode<T> *ht = new HuffNode<T>[2 * n - 1]; //一个含有n个叶子结点的最优二叉树,总共有2*n-1个结点
27 HuffNode<T> *huffNode = ht;
28 for (i = 0; i < 2 * n - 1; i++) //最优二叉树结点数组初始化
29 {
30 huffNode[i].weight = 0; //权值都设为0
31 huffNode[i].parent = -1; //父节点,左右孩子结点
32 huffNode[i].lch = -1;
33 huffNode[i].rch = -1; //都设置为-1,-1代表空
34 }
35 for (i = 0; i < n; i++) //依次输入n个叶子结点的权值
36 cin >> huffNode[i].weight;
37
38 for (i = 0; i < n - 1; i++)
39 {
40 min1 = min2 = MAX_VALUE;
41 // x1, x2 用来保存找到的两个最小结点在数组中的位置
42 x1 = x2 = 0;
43 for (j = 0; j < n + i; j++) //因为外循环每循环一次,实际结点个数增加到n+i个
44 {
45 if (huffNode[j].weight < min1 && huffNode[j].parent == -1)
46 {
47 min2 = min1; //存在权值小于min1, 则min1赋值给次小值
48 x2 = x1; //次小值下标改变
49 min1 = huffNode[j].weight; //当前权值赋值给最小值
50 x1 = j; //并保存最小值下标
51 }
52 else if (huffNode[j].weight < min2 && huffNode[j].parent == -1)
53 {
54 min2 = huffNode[j].weight; //当前值赋值给次小值
55 x2 = j; //保存次小值下标
56 }
57 }
58 //将找出的两个子树合并成一颗子树
59 //对找到的两个最小结点的父指针域进行赋值
60 huffNode[x1].parent = n + i;
61 huffNode[x2].parent = n + i;
62 //新合成树位置上的权值
63 huffNode[n + i].weight = huffNode[x1].weight + huffNode[x2].weight;
64 //两个最小结点的父结点的左右孩子域进行操作
65 huffNode[n + i].lch = x1;
66 huffNode[n + i].rch = x2;
67 }
68 return ht;
69 }
70
71 template<typename T>
72 void ShowHTree(HuffNode<T> *HT, int nodeNum)
73 {
74 HuffNode<T> *p = HT;
75 int k;
76 cout << "k" << "\t\t" << "Weight" << "\t\t" << "Parent"
77 << "\t\t" << "Lchild" << "\t\t" << "Rchild" << endl;
78 for (k = 0; k < 2 * nodeNum - 1; k++)
79 {
80 cout << k << "\t\t" << (p + k)->weight << "\t\t"
81 << (p + k)->parent << "\t\t"
82 << (p + k)->lch << "\t\t" << (p + k)->rch << endl;
83 }
84 }
85
86 /*************************编码*******************************/
87
88 const int MAXBIT = 50; //定义Huffman编码的最大长度
89
90 //对于第i个字符,它的Huffman编码存放在Huffman[i].bit中的 从 Huffman[i].start 到 n 的分量中
91 struct HCodeType {
92 int bit[MAXBIT]; //用来保存字符 的 Huffman编码
93 int start; //start表示该编码在bit中的开始位置
94 };
95
96 void HuffmanCode(int n)
97 {
98 const int MAXODE = 50, MAXLEAF = 50; //最大编码长度,最多叶子数
99 HuffNode<int> *huffNode; //用于 生成Huffman 编码
100 HCodeType *huffCode, cd;
101 int i, j, c, par, sign = 0;
102
103 huffNode = HuffmanTree(n, sign); //建立Huffman树
104
105 huffCode = new HCodeType[n]; //初始化HuffCode
106 for (int k = 0; k < n; k++)
107 huffCode[k].bit[i] = 0;
108
109 ShowHTree(huffNode, n);
110
111 /**********************编码过程*************************/
112 for (i = 0; i < n; i++) //n--是叶结点数,不是全部结点数
113 {
114 cd.start = n - 1; //从叶结点开始
115 c = i; //c为 i的工作指针,以防误操作修改了 i
116 par = huffNode[c].parent;
117 while (par != -1) //由叶结点向上直到树根
118 {
119 if (huffNode[par].lch == c) //右子树编号 == c ==> 右是0标志
120 cd.bit[cd.start] = 0;
121 else //左是 1 标志
122 cd.bit[cd.start] = 1;
123 cd.start--; //开始位置向前
124 c = par; //得到父亲结点的下标
125 par = huffNode[c].parent; //由叶结点向上直到树根 -- 得到父级点的父亲结点
126 }
127 for (j = cd.start + 1; j < n; j++) //保存求出的每个叶结点的哈夫曼编码和编码的起始位
128 {
129 huffCode[i].bit[j] = cd.bit[j];
130 }
131 huffCode[i].start = cd.start; //设置编码的开始位置
132 }
133
134 //输出
135 for (i = 0 ; i < n; i++) //输出每个叶子结点的哈夫曼编码
136 {
137 for (j = huffCode[i].start + 1; j < n; j++) {
138 cout << huffCode[i].bit[j] ;
139 }
140 cout << endl;
141 }
142 }
143
144 int main()
145 {
146 int n;
147
148 cout << "请输入叶子结点个数: " << endl;
149 cin >> n;
150
151 HuffmanCode(n);
152
153 system("pause");
154
155 return 0;
156 }