c语言哈夫曼树和哈夫曼编码(基础篇c+提升优先队列c++)

以下代码时以数据结构预算法设计课本标准而来,是以c语言为基础写的。当然改进的话可以用优先队列来实现最小值的查找。

哈夫曼树和哈夫曼编码的意义在于将字符串等用二进制数来代替(也可以理解为加密的过程),代替后的二进制数最短且可以翻译为原字符串(解密)。哈夫曼的内在原理可以查阅其他文本资料,在这里我就不加以赘述了。

整体代码实现(基础c): 

#include<iostream>
#include<climits>
#define K 100
using namespace std;
typedef struct{//哈夫曼树
	char data;  //字符
	int weight; //对应权值
	int parent,lchild,rchild;
}HTNode;
typedef struct{ //哈夫曼编码
	char cd[K]; //字符对应的哈夫曼编码
	int start;  //cd[]的起始位置
}HCode;
void CreathufTree(HTNode ht[],int n){  //哈夫曼数的创建
	int lnode,rnode,min1,min2;  //lnode和rnode记录左右子节点,min1和min2用来寻找最小的两个数
	for(int i=0;i<2*n-1;i++)  //初始化,将所有的节点都设置为单根树,n个结点对应2*n-1个结点
		ht[i].parent=ht[i].lchild=ht[i].rchild=-1;  //双亲、左、右都没有
	for(int i=n;i<2*n-1;i++){  //创建
		lnode=rnode=-1;  //开始记录左、右树
		min1=min2=INT_MAX; //记录最小值
		for(int k=0;k<i;k++){  //从i之前的所有的子树权值取最小的两个
			if(ht[k].parent==-1){  
				if(ht[k].weight<min1){   //每次循环先比较min1,找到最小的,在比较min2
					min2=min1; rnode=lnode; min2记录min1的前一个值
					min1=ht[k].weight; lnode=k;
				}else if(ht[k].weight<min2){  //找到倒数第二小的
					rnode=k; min2=ht[k].weight;
				}
			}
		}
		ht[i].lchild=lnode; ht[i].rchild=rnode;  //处理双亲
		ht[i].weight=ht[lnode].weight+ht[rnode].weight;
		ht[lnode].parent=i; ht[rnode].parent=i;
	}
}
void CreatHCode(HTNode ht[],HCode hcd[],int n){ //创建哈夫曼编码
	int f,c;   //记录c的双亲
	HCode hc;  //用于遍历所有结点时赋值
	for(int i=0;i<n;i++){   //从i到n-1记录的时叶子结点
		hc.start=n;  //从叶子结点开始遍历,所以先把指针指向最后一个进行储存
		c=i;   //标记该结点
		f=ht[i].parent;  //找到双亲
		while(f!=-1){  //不是根节点
			if(ht[f].lchild==c) hc.cd[--hc.start]='0';  //如果c在双亲左边
			else hc.cd[--hc.start]='1';  //右边
			c=f;  //类似于回溯,将c的双亲变为当前结点,找其双亲
			f=ht[f].parent; //找双亲
		}
		hcd[i]=hc;  //记录每个字符的哈夫曼编码
	}
}
int main(){
	int n;
	cout<<"请输入字符数:";
	cin>>n;
	HTNode ht[2*K];
	HCode hcd[K];
	for(int i=0;i<n;i++){
		cout<<"请输入字符"<<i+1<<":";
		cin>>ht[i].data;
		cout<<"请输入对应权值:";
		cin>>ht[i].weight;
	}
	CreathufTree(ht,n);
	CreatHCode(ht,hcd,n);
	cout<<1;
	cout<<"哈夫曼树:"<<endl; 
	for(int i=0;i<2*n-1;i++){
		cout << "Node " << i << ": ";
        cout << "Data: " << ht[i].data << ", ";
        cout << "Weight: " << ht[i].weight << ", ";
        cout << "Parent: " << ht[i].parent << ", ";
        cout << "Left Child: " << ht[i].lchild << ", ";
        cout << "Right Child: " << ht[i].rchild << endl;
	}
	cout<<"哈夫曼编码:"<<endl;
	for(int i=0;i<n;i++){
		cout<<ht[i].data<<":";
		for(int j=hcd[i].start;j<n;j++)
			cout<<hcd[i].cd[j];
		cout<<endl;
	}
}

提升c++(采用优先队列): 

没时间写解释了,自行理解吧,加油。

#include <iostream>
#include <queue>
using namespace std;
struct HTNode {
    char data;
    int weight;
    struct HTNode *parent, *lchild, *rchild;
};
struct compare {
    bool operator()(HTNode* a, HTNode* b) {
        return a->weight > b->weight;
    }
};
HTNode* CreateHuffmanTree(priority_queue<HTNode*, vector<HTNode*>, compare>& dp) {
	while (dp.size() > 1) {
        HTNode* p = dp.top();
        dp.pop();
        HTNode* q = dp.top();
        dp.pop();
        HTNode* s = new HTNode;
        s->weight = p->weight + q->weight;
        s->lchild = p;
        s->rchild = q;
        p->parent = q->parent = s;
        dp.push(s);
    }
    return dp.top();
}

void GenerateHuffmanCode(HTNode* root, string code) {
    if (!root) return;
    if (!root->lchild && !root->rchild) {
        cout << root->data << ":" << code << endl;
        return;
    }
    GenerateHuffmanCode(root->lchild, code + "0");
    GenerateHuffmanCode(root->rchild, code + "1");
}

int main() {
    int n;
    cout << "请输入字符数:";
    cin >> n;
    priority_queue<HTNode*, vector<HTNode*>, compare> dp;
    for (int i = 0; i < n; i++) {
        HTNode* p = new HTNode;
        cout << "请输入字符:";
        cin >> p->data;
        cout << "请输入权值:";
        cin >> p->weight;
        p->parent = p->lchild = p->rchild = NULL;
        dp.push(p);
    }
    HTNode* root = CreateHuffmanTree(dp);
    cout << "哈夫曼编码结果:" << endl;
    GenerateHuffmanCode(root, "");
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值