数据结构-赫夫曼树

来源:互联网 发布:新网域名转阿里云 编辑:程序博客网 时间:2024/06/06 00:24

引言:

赫夫曼编码是属于一种变长编码形式。它在压缩领域有重要的运用。可以利用二叉树来构建赫夫曼树来对信号进行编码。该树的构造思想是:对于有n个叶子节点(既是需要编码的字符数)的赫夫曼树,应该有2*n-1个结点(整个赫夫曼树的总结点数)。在树进行构造的时候输入的参数是长度为2*n-1的静态链表(类型为赫夫曼树的数据类型)首指针,该静态链表的前n个位置存放叶子结点,后面的n-1个结点存放的是分支节点。

在初始化赫夫曼树时,把前面n个叶子结点的权值域与数据域用指定的值(字符数组与权值数组)进行填充,n-1个分支结点的权值域用0填充,其它域用-1进行填充。然后,在结点中寻找两个权值最小的结点node1与node2,最后用这两个权值最小的结点构造一个新的二叉树。对于已经构造了二叉树的结点,就不能在此参与构造新的二叉树了,但是这棵二叉树的根节点可以参加构造新二叉树。在初始化时,结点的双亲标志位(parent)被设置为-1,在构造二叉树时,参与构造二叉树的两个结点node1与node2的双亲标志位被设置为它们的根结点,这样它们的双亲标志位(域)就不是-1了,也就与未参与构造二叉树的结点区分开了。接下来上代码...

实现代码

赫夫曼树存储结构:

typedef char datatype;//Huffman数据类型别名typedef struct Node2 {datatype data;//数据域unsigned int weight;//权值域int parent;//父结点域int left;//左孩子int right;//右孩子}HufNode, *PHufNode;<span style="font-family:Microsoft YaHei;"></span>


赫夫曼树的构建:

/************************************************************************//*初始化并且建立Huffman树参数:weight权值数组n个参数:data数据数组n个参数:num权值与数据的个数n个参数:hufnodehuffman节点数组n-1个返回值:成功true 失败false*//************************************************************************/bool CHuffman::InitHufTree(const int* weight, const datatype* data, const int num, PHufNode hfnode){//首先检查数据域是否为空 若为空返回if ((nullptr==weight) || (nullptr==data) || (nullptr==hfnode)){std::cout << "\nthere could be a empty input pointer,please check!\n";return false;}//接下来应该有weight与data数组元素个数是否相等之类的检查//初始化huffman树for (int i=0; i<(2*num-1); i++){if (i < num)//初始化num个叶子节点{hfnode[i].data = data[i];//赋值数据域hfnode[i].weight = weight[i];//赋值权值域}else//初始化num-1个分支结点{hfnode[i].weight = 0;//对于不是huffman叶子结点的结点的权值设置为0}hfnode[i].parent = -1;hfnode[i].left = -1;hfnode[i].right = -1;}unsigned int mw1(100), mw2(100);//权值计算中间变量int node1(-1), node2(-1);//结点连接中间变量for (int i=num; i<(2*num-1); i++){mw1 = mw2 = 100;node1 = node2 = -1;for (int j=0; j<i; j++)//在节点(父节点域=-1)中寻找两个权值最小的节点node1和node2{//最后node2的权值大于node1的权值 因为node2在node1的右边if (-1 == hfnode[j].parent){if (mw1 > hfnode[j].weight){mw2 = mw1;node2 = node1;mw1 = hfnode[j].weight;node1 = j;}else if(mw2 > hfnode[j].weight){mw2 = hfnode[j].weight;node2 = j;}}}//用node1和node2构造一颗新的二叉树,二叉树根的权值为node1和node2权值的和hfnode[i].weight = hfnode[node1].weight + hfnode[node2].weight;hfnode[node1].parent = i;hfnode[node2].parent = i;//填充选出来的根节点的左右孩子域hfnode[i].left = node1;hfnode[i].right = node2;}return true;}


获取相应单个字符的编码:

/************************************************************************//* 获取单个元素的Huffman编码参数:hfnode霍夫曼树参数:data_pos需要编码的霍夫曼字符0~(N-1)参数:N编码的总个数返回值:成功true 失败false*//************************************************************************/bool CHuffman::GetItemHufCode(PHufNode hfnode, const int data_pos, const int N){if (nullptr == hfnode){std::cout << "\nempty input error!\n";return false;}if (data_pos > (N-1)){std::cout << "\nthe input pos is out of range!\n";return false;}unsigned int parent = hfnode[data_pos].parent;unsigned int left = data_pos;std::cout << "\n" <<  hfnode[data_pos].data << ":";while (-1 != parent)//没有达到根节点{if (left == hfnode[parent].left)std::cout << "0";elsestd::cout << "1";left = parent;parent = hfnode[parent].parent;}return true;}

赫夫曼树的层序遍历:

不是叶子结点的结点输出‘-’

void CHuffman::TravelByLevel(PHufNode hfnode, const int num){std::cout << "\n";std::vector<HufNode> vec;vec.push_back(hfnode[2*num-2]);unsigned int cur(0), end(1);while (cur < vec.size()){end = vec.size();while (cur < end){if (NULL != vec[cur].data)std::cout << vec[cur].data << " ";elsestd::cout << "-" << " ";if (-1 != vec[cur].left)//若左孩子不为空将其放入向量中{vec.push_back(hfnode[vec[cur].left]);//压入数据}if (-1 != vec[cur].right)//若右孩子不为空将其放入向量中{vec.push_back(hfnode[vec[cur].right]);//压入数据}cur++;}std::cout << "\n";}}


上述如若有错欢迎指正^_^


0 0
原创粉丝点击