前言:
首先感谢这博主的思路,谢谢,再次感谢。在哈夫曼树结构指针时卡断了,看了这个博主的就会了,万分感谢!https://blog.csdn.net/qq_37787333/article/details/89160075
相关概念:
概念
给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
数据解压缩
简单来说,哈夫曼码树的解压缩就是将得到的前置码(Prefix Huffman code)转换回符号,通常借由树的追踪(Traversal),将接收到的比特串(Bits stream)一步一步还原。但是要追踪树之前,必须要先重建哈夫曼树;某些情况下,如果每个符号的权重可以被事先预测,那么哈夫曼树就可以预先重建,并且存储并重复使用,否则,发送端必须预先发送哈夫曼树的相关信息给接收端 。
相关代码:
#include<iostream>
using namespace std;
#define maxval 10000
#define maxsize 100 //哈夫曼编码的最大位数
typedef struct
{
char ch;
int weight;
int lchild,rchild,parent;
}hufmtree;
typedef struct
{
char bits[10]; //位串
int start; //编码在位串中的起始位置
char ch; //字符
}codetype;
void huffman(hufmtree tree[] ,int n,int m)//建立哈夫曼树
{
int i,j,p1,p2;//p1,p2分别记住每次合并时权值最小和次小的两个根结点的下标
int small1,small2,f;
char c;
for(i=0;i<m;i++) //初始化
{
tree[i].parent=0;
tree[i].lchild=-1;
tree[i].rchild=-1;
tree[i].weight=0;
}
for(i=0;i<n;i++) //读入前n个结点的字符及权值
{
cout<<"输入第"<<i+1<<"个元素的=>"<<endl;
cout<<"\t节点的值: ";
cin>>c;
tree[i].ch=c;
cout<<"\t权值: ";
cin>>f;
tree[i].weight=f;
}
for(i=n;i<m;i++) //进行n-1次合并,产生n-1个新结点
{
p1=0;p2=0;
small1=maxval;small2=maxval; //maxval是float类型的最大值
for(j=0;j<i;j++) //选出两个权值最小的根结点
if(tree[j].parent==0)
if(tree[j].weight<small1)
{
small2=small1; //改变最小权、次小权及对应的位置
small1=tree[j].weight;
p2=p1;
p1=j;
}
else
if(tree[j].weight<small2)
{
small2=tree[j].weight; //改变次小权及位置
p2=j;
}
tree[p1].parent=i;
tree[p2].parent=i;
tree[i].lchild=p1; //最小权根结点是新结点的左孩子
tree[i].rchild=p2; //次小权根结点是新结点的右孩子
tree[i].weight=tree[p1].weight+tree[p2].weight;
}
}//huffman
void huffmancode(codetype code[],hufmtree tree[],int n)//根据哈夫曼树求出哈夫曼编码
//codetype code[]为求出的哈夫曼编码
//hufmtree tree[]为已知的哈夫曼树
{
int i,c,p;
codetype cd; //缓冲变量
for(i=0;i<n;i++)
{
cd.start=n;
cd.ch=tree[i].ch;
c=i; //从叶结点出发向上回溯
p=tree[i].parent; //tree[p]是tree[i]的双亲
while(p!=0)
{
cd.start--;
if(tree[p].lchild==c)
cd.bits[cd.start]='0'; //tree[i]是左子树,生成代码'0'
else
cd.bits[cd.start]='1'; //tree[i]是右子树,生成代码'1'
c=p;
p=tree[p].parent;
}
code[i]=cd; //第i+1个字符的编码存入code[i]
}
}//huffmancode
void decode(hufmtree tree[],int m)//依次读入电文,根据哈夫曼树译码
{
int i,j=0;
char b[maxsize];
char endflag='#'; //电文结束标志取#
i=m-1; //从根结点开始往下搜索
cout<<"请输入电文(0 or 1),以'#'为结束标志:"<<endl;
cin>>b;
cout<<"输出哈夫曼编码:\n";
while(b[j]!='#')
{
if(b[j]=='0')
i=tree[i].lchild; //走向左孩子
else
i=tree[i].rchild; //走向右孩子
if(tree[i].lchild==-1) //tree[i]是叶结点
{
cout<<tree[i].ch;
i=m-1; //回到根结点
}
j++;
}
cout<<endl;
if(tree[i].lchild!=-1&&b[j]!='#') //电文读完,但尚未到叶子结点
cout<<"\nERROR\n"; //输入电文有错
}//decode
int main()
{
int choice=0;
int n,m;
int i,j;//循环变量
char ch;
hufmtree *tree;
codetype *code;
do{
cout<<"\t\t请选择您要所实现的功能:(请输入1-4数字)\n";
cout<<"\t1---建立哈夫曼树\n";
cout<<"\t2---编码\n";
cout<<"\t3---译码\n";
cout<<"\t4---退出系统\n";
cin>>choice;
switch(choice){
case 1:
cout<<"请输入元素个数:";
cin>>n;
m=2*n-1;
tree=new hufmtree[m];
code=new codetype[n];
huffman(tree,n,m);//建立哈夫曼树
cout<<"哈夫曼树已成功建立!\n";
break;
case 2:
huffmancode(code,tree,n);//根据哈夫曼树求出哈夫曼编码
cout<<"输出哈夫曼编码\n"<<endl;
for(i=0;i<n;i++)
{
cout<<code[i].ch<<": ";
for(j=code[i].start;j<n;j++)
cout<<code[i].bits[j];
cout<<endl;
}
break;
case 3:
decode(tree,m);//依次读入电文,根据哈夫曼树译码
break;
default:
break;
}
cout<<"是否继续:?(Y)"<<endl;
cin>>ch;
}while(ch=='Y'||ch=='y');
return 0;
}
后记:
想一想间谍,嘻嘻,快动用自己的脑洞编程吧!