哈夫曼树(创建;编码;译码)

前言:

首先感谢这博主的思路,谢谢,再次感谢。在哈夫曼树结构指针时卡断了,看了这个博主的就会了,万分感谢!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;
}

后记:

想一想间谍,嘻嘻,快动用自己的脑洞编程吧!

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

threecat.up

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值