Huffman树及其编码(STL array实现)

这篇随笔主要是Huffman编码,构建哈夫曼树有各种各样的实现方法,如优先队列,数组构成的树等,但本质都是堆。

这里我用数组来存储数据,以堆的思想来构建一个哈弗曼树,并存入vector中,进而实现哈夫曼编码

 

步骤:  1生成哈夫曼树  (取最小权值树和次小权值树生成新树,排列后重新取树,不断重复)

        2编码   (遵循左零右一的原则)

             3解码(是编码的逆向,本文还未实现,日后有机会补充)

data.txt  测试数据:


5
1 2 3 4 5
abcde

结果:

下面贴代码:

  1 #include <iostream>
  2 #include <fstream>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <array>
  6
  7 using namespace std;
  8
  9 #define ARR_SIZE 100   //缓冲区大小
 10
 11 typedef struct Tree
 12 {
 13     int freq;
 14     char key = ‘\0‘;
 15     Tree *left, *right;
 16     Tree()
 17     {
 18         freq = 0;
 19         key = ‘\0‘;
 20         left = NULL;
 21         right = NULL;
 22     }
 23 } Tree, *pTree;
 24 union key_or_point
 25 {
 26     char key;
 27     pTree point;
 28 };
 29 enum infor_type
 30 {
 31     key_s,
 32     point_s
 33 };
 34 class infor
 35 {
 36 public:
 37     int freq;//权值
 38     key_or_point kp;//记录键值或者 新生成的树的地址
 39     infor_type type;//  联合体key_or_point的类型由infor_type标志
 40     infor()
 41     {
 42         freq = 0;
 43         kp.key = NULL;
 44         type = key_s;
 45     }
 46 };
 47
 48 array<infor, ARR_SIZE> arr;//用来读取要处理的数据
 49 vector<pTree> trees;  //所有生成的树都放在vector里面
 50
 51 int num;   //要处理的数据个数
 52
 53 bool cmp(infor a, infor b)
 54 {
 55     return a.freq > b.freq;
 56 }
 57
 58 void Huffman()
 59 {
 60     //找出最小权值和次小权值
 61     sort(&arr[0], &arr[num], cmp);
 62     int cal = num - 1;
 63     while (cal > 0)
 64     {
 65
 66         pTree pta = new Tree();
 67         vector<pTree>::iterator it;
 68
 69         pTree ptl = new Tree();
 70         ptl->freq = arr[cal].freq;
 71         // pt all 的左子树
 72         if (arr[cal].type == point_s)
 73         {
 74             pta->left = arr[cal].kp.point;//如果存放的是地址,那么该树已入vector
 75             //无需重复操作
 76         }
 77         else
 78         {
 79             ptl->key = arr[cal].kp.key;
 80             trees.push_back(ptl);
 81             it = trees.end() - 1;
 82             pta->left = *it;
 83         }
 84
 85
 86         pTree ptr = new Tree();
 87         ptr->freq = arr[cal - 1].freq;
 88         // pt all 的右子树
 89         if (arr[cal - 1].type == point_s)
 90         {
 91             pta->right = arr[cal - 1].kp.point; //如果存放的是地址,那么该树已入vector
 92             //无需重复操作
 93         }
 94         else
 95         {
 96             ptr->key = arr[cal - 1].kp.key;
 97             trees.push_back(ptr);
 98             it = trees.end() - 1;
 99             pta->right = *it;
100         }
101
102         pta->freq = arr[cal].freq + arr[cal - 1].freq;
103         trees.push_back(pta);//pt all 本树
104
105         it = trees.end() - 1;
106         arr[cal - 1].kp.point = *it;
107         arr[cal - 1].type = point_s;//保存新生成树的地址
108
109         arr[cal - 1].freq = arr[cal - 1].freq + arr[cal ].freq;
110         //最小权值的树和次权值的树组成新树后,放回原数组
111         //新树的key_or_point此时类型变为point_s指针指向vector存放的位置
112
113         //第一次循环会有三棵树入vector,重新排列后,新树无需重复入vector
114         cal--;
115         sort(&arr[0], &arr[cal + 1], cmp);
116
117     }
118
119 }
120
121 void traversTree(pTree pt, string st = "")
122 {
123     //中序遍历二叉树
124     //遵循左0右1的原则
125     if (pt->left == NULL && pt->right == NULL)
126     {
127         cout.flags(ios::left);
128         cout.width(10);
129         cout << st.c_str() << "  ";
130         cout << pt->key << endl;
131         return;
132     }
133     if (pt->left != NULL)
134     {
135         st += ‘0‘;
136         traversTree(pt->left, st);
137         st.pop_back();//从左边出来后要回退一个字符,避免进入右边时多出一个字符
138     }
139
140     if (pt->right != NULL)
141     {
142         st += ‘1‘;
143         traversTree(pt->right, st);
144     }
145     return ;
146 }
147
148 void printCode()
149 {
150     vector<pTree>::iterator it;
151     it = trees.end() - 1;
152     pTree pt = *it; //取出最顶端的树
153     cout << "print HuffmanCode:" << endl;
154     traversTree(pt);
155 }
156 int main()
157 {
158     ifstream filein("data.txt");
159     cin.rdbuf(filein.rdbuf());//重定向输入
160     cin >> num;//要处理的数据个数
161     for (int i = 0; i < num; i++)
162     {
163         cin >> arr[i].freq;
164     }
165     for (int i = 0; i < num; i++)
166     {
167         cin >> arr[i].kp.key;
168     }
169     Huffman();
170     printCode();
171     return 0;
172 }

分析:

这是以上测试数据生成的树的情况。

只有叶子节点表示有效的符号,所以遍历树时返回条件是叶子节点(如果是叶子节点则返回)

总结:

1 编程时用的一些小技巧总结:

  1.1  输出调试信息:可以采用如下方式

      #ifdef DEBUG

        cout调试信息....

      #endif

  1.2 联合体union需要取得类型时,可以加一个enum来记录和标志uninon的类型

2  编程方法反思:

  可以看到源码中用到了两次sort,这是省事的做法了。

  目前想到的改进的方法是用二分插入(数据已经排序)

  

  对比起来,我觉得优先队列的方式更易懂且效率更高,但此文也算是一次小探索,值得记录下来

3 感想:

  本人入园第一次随笔,如有不足或错误,还望指出。

以上

原文地址:https://www.cnblogs.com/virgildevil/p/10349693.html

时间: 2024-10-12 20:30:51

Huffman树及其编码(STL array实现)的相关文章

Huffman树的编码译码

上个学期做的课程设计,关于Huffman树的编码译码. 要求: 输入Huffman树各个叶结点的字符和权值,建立Huffman树并执行编码操作 输入一行仅由01组成的电文字符串,根据建立的Huffman树进行译码操作,程序最后输出译码后的结果 Huffman.h定义了树的结点信息,各种操作.GCC编译通过. 1 #ifndef HUFFMAN_H_INCLUDED 2 #define HUFFMAN_H_INCLUDED 3 #include <iostream> 4 #include <

Huffman树与编码

带权路径最小的二叉树称为最优二叉树或Huffman(哈夫曼树). Huffman树的构造 将节点的权值存入数组中,由数组开始构造Huffman树.初始化指针数组,指针指向含有权值的孤立节点. b = malloc(n*sizeof(BTreeNode)); for (i = 0; i < n; i++) { b[i] = malloc(sizeof(BTreeNode)); b[i]->data = a[i]; b[i]->left = NULL; b[i]->right = NU

数据结构复习之利用Huffman树进行编码和译码

//编码#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<fstream> #include<map> using namespace std; typedef struct HuffmanNode{ int w;//节点的权值

Huffman树费用

问题描述 Huffman树在编码中有着广泛的应用.在这里,我们只关心Huffman树的构造过程. 给出一列数{pi}={p0, p1, -, pn-1},用这列数构造Huffman树的过程如下: 1. 找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,然后将它们的和加入到{pi}中.这个过程的费用记为pa + pb. 2. 重复步骤1,直到{pi}中只剩下一个数. 在上面的操作过程中,把所有的费用相加,就得到了构造Huffman树的总费用. 本题任务:对于给定的一个数列

Huffman树及其编解码

Huffman树--编解码 介绍: ??Huffman树可以根据输入的字符串中某个字符出现的次数来给某个字符设定一个权值,然后可以根据权值的大小给一个给定的字符串编码,或者对一串编码进行解码,可以用于数据压缩或者解压缩,和对字符的编解码. ??可是Huffman树的优点在哪? ??1.就在于它对出现次数大的字符(即权值大的字符)的编码比出现少的字符编码短,也就是说出现次数越多,编码越短,保证了对数据的压缩. ??2.保证编的码不会出现互相涵括,也就是不会出现二义性,比如a的编码是00100,b的

哈夫曼(Huffman)树与哈夫曼编码

声明:原创作品,转载时请注明文章来自SAP师太技术博客:www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4289610.html 哈夫曼树又称最优二叉树,是一种带权路径长最短的树.树的路径长度是从树根到每一个叶子之间的路径长度之和.节点的带树路径长度为从该节点到树根之间的路径长度与该节点权(比如字符在某串中的使用频率)的乘积. 比如有一串字符串如

哈夫曼(Huffman)树和哈夫曼编码

一.哈夫曼(Huffman)树和哈夫曼编码 1.哈夫曼树(Huffman)又称最优二叉树,是一类带权路径长度最短的树, 常用于信息检测. 定义: 结点间的路径长度:树中一个结点到另一个结点之间分支数目称为这对结点之间的路径长度. 树的路径长度:树的根结点到树中每一结点的路径长度之和. 带权路径长度:从根结点到某结点的路径长度与该结点上权的乘积. 树的带权路径长度:树中所有叶子结点的带权路径长度之和记为WPL. 例如: 对图(a): WPL =9×2+5×2+2×2+3×2=38 对图(b): W

数据结构之huffman树

#include <stdio.h> #include<stdlib.h> #define MAXBIT      99 #define MAXVALUE  9999 #define MAXLEAF     30 #define MAXNODE    MAXLEAF*2 -1 typedef struct  {     int bit[MAXBIT];     int start; } HCodeType;        /* 编码结构体 */ typedef struct {  

数据结构之Huffman树与最优二叉树

最近在翻炒一些关于树的知识,发现一个比较有意思的二叉树,huffman树,对应到离散数学中的一种名为最优二叉树的路径结构,而Huffman的主要作用,最终可以归结到一种名为huffman编码的编码方式,使用huffman编码方式,我们可以以平均长度最短的码字来记录一串信息,且每个信息分子的编码唯一,独立.从而最终合成编码所对应的信息唯一,无歧义. huffman树的创建时基于每个信息分子都拥有其权重,权重越大,越靠近树根,即路径越短, 下面我们我们来以一个huffman树的例子为例:简单引入一下