【数据结构】哈夫曼树的创建与基础应用

本文介绍如何根据给定的n个权值创建哈夫曼树,并详细讲解了构建过程,包括节点结构、查找函数以及生成节点的哈夫曼编码。还提供了完整的C++代码实现。
摘要由CSDN通过智能技术生成

根据给定的n个权值生成哈夫曼二叉树,输出赫夫曼编码及进行译码

哈夫曼树的结点的结构体

struct huffmannode//哈夫曼树结点的结构体 
{
	int weight;//结点权重 
	
	int parent;//父结点 
	
	int leftchild;//左子树 
	
	int rightchild;	//右子树 
};

建树

void creat_tree(huffmannode tree[], int w[],int n)//建哈夫曼树 
{
	int node1 = 0, node2 = 0;
	
	for(int i=0;i<2*n-1;++i)//初始化结点 
	{
		tree[i].parent = -1;
		
		tree[i].leftchild = -1;
		
		tree[i].rightchild = -1;
	}
	
	for(int i=0;i<n;++i)//将输入的结点值输入哈夫曼树 
	{
		tree[i].weight = w[i];
	}
	
	for(int k=n;k<2*n-1;++k)
	{
		select(tree,k,node1,node2);//找到最小结点,次小结点 
		
		tree[k].weight = tree[node1].weight + tree[node2].weight;//生成新结点,权重为两结点之和 
		
		tree[node1].parent = k;//最小结点父结点为新结点 
		
		tree[node2].parent = k;//次小结点父结点为新结点 
		
		tree[k].leftchild = node1;//新结点左子树为最小结点 
		
		tree[k].rightchild = node2;//新结点右子树为次小结点 
	}
}

思路:将最开始输入的结点放入待选择结点列表,不断选择权重最小与权重次小的结点,用他们生成新的结点,并使新结点成为他们的父结点,再将新结点也放入待选择的结点列表,直至新生成了n-1个结点,此时该父结点也为根结点,最后这2*n-1个结点就成为了哈夫曼树。

建树时使用的查找函数

void select(huffmannode tree[],int k,int &node1,int &node2)//在尚未使用的结点中,找到两个权重最小的结点 
{
	node1 = -1, node2 = -1;//初始化两个没有父结点的最小结点的位置 
	
	int minweight = 1e8;//初始化最小权重 
	
	for(int i=0;i<k;++i)
	{
		if(tree[i].parent==-1)//没有父结点 
		{
			if(tree[i].weight<minweight)//小于最小权重 
			{
				minweight = tree[i].weight;//更新最小权重 
				
				node1 = i;//更新最小点位置 
			}
		}
	}
	
	minweight = 1e8;//初始化权重 
	
	for(int i=0;i<k;++i)
	{
		if(tree[i].parent==-1&&i!=node1)//没有父结点且不是最小结点 
		{
			if(tree[i].weight<minweight)//更新次小结点 
			{
				minweight = tree[i].weight;
				
				node2 = i;
			}
		}
	}
}

思路:两遍遍历,第一遍找到未连接父结点且权重最小的点,将其标记为node1;第二遍,找到除了node1之外,未连接父结点且权重最小的点,将其标记为node2.

生成结点对应的哈夫曼编码

void form_code(huffmannode tree[],int n)//生成哈夫曼编码 
{
	int cur, parent, start;
	
	string huffcode;
	
	for(int i=0;i<n;++i)//遍历n个输入的结点 
	{
		cur = i;
		
		parent = tree[i].parent;
		
		while(parent!=-1)//当没有到达根结点,向上寻找父结点 
		{
			if(tree[parent].leftchild==cur)//如果当前结点是左子树 
			{
				huffcode = '0' + huffcode;//在哈夫曼编码前加0 
			}
			else
			{
				huffcode = '1' + huffcode;//加1 
			}
			
			cur = parent;//更新当前结点 
			
			parent = tree[parent].parent;//更新父结点 
		}
		
		code[tree[i].weight] = huffcode;//将生成的哈夫曼编码用map保存 
		
		translate[huffcode] = ch[i];//将哈夫曼编码对应的值保存 
		
		huffcode.clear();//清空哈夫曼编码 
	}
}

思路:分别以n个输入的结点为起点,不断向上寻找它的父结点,直到父结点到达根结点,如果对于父结点来讲,当前结点是左子结点,则在已生成的哈夫曼编码前加上0,如果是右子结点,则加上1。在生成完整编码后用map容器保存编码。

完整代码

#include<iostream>
#include<cstdio>
#include<string>
#include<map>

using namespace std;

const int Size = 1e4+5;

struct huffmannode//哈夫曼树结点的结构体 
{
	int weight;//结点权重 
	
	int parent;//父结点 
	
	int leftchild;//左子树 
	
	int rightchild;	//右子树 
};

map<int,string> code;//保存值对应的哈夫曼编码 

map<string,char> translate;//保存哈夫曼编码对应的值 

map<char,int> alp;

char ch[105];
	
int w[105];

void select(huffmannode tree[],int k,int &node1,int &node2)//在尚未使用的结点中,找到两个权重最小的结点 
{
	node1 = -1, node2 = -1;//初始化两个没有父结点的最小结点的位置 
	
	int minweight = 1e8;//初始化最小权重 
	
	for(int i=0;i<k;++i)
	{
		if(tree[i].parent==-1)//没有父结点 
		{
			if(tree[i].weight<minweight)//小于最小权重 
			{
				minweight = tree[i].weight;//更新最小权重 
				
				node1 = i;//更新最小点位置 
			}
		}
	}
	
	minweight = 1e8;//初始化权重 
	
	for(int i=0;i<k;++i)
	{
		if(tree[i].parent==-1&&i!=node1)//没有父结点且不是最小结点 
		{
			if(tree[i].weight<minweight)//更新次小结点 
			{
				minweight = tree[i].weight;
				
				node2 = i;
			}
		}
	}
}

void creat_tree(huffmannode tree[], int w[],int n)//建哈夫曼树 
{
	int node1 = 0, node2 = 0;
	
	for(int i=0;i<2*n-1;++i)//初始化结点 
	{
		tree[i].parent = -1;
		
		tree[i].leftchild = -1;
		
		tree[i].rightchild = -1;
	}
	
	for(int i=0;i<n;++i)//将输入的结点值输入哈夫曼树 
	{
		tree[i].weight = w[i];
	}
	
	for(int k=n;k<2*n-1;++k)
	{
		select(tree,k,node1,node2);//找到最小结点,次小结点 
		
		tree[k].weight = tree[node1].weight + tree[node2].weight;//生成新结点,权重为两结点之和 
		
		tree[node1].parent = k;//最小结点父结点为新结点 
		
		tree[node2].parent = k;//次小结点父结点为新结点 
		
		tree[k].leftchild = node1;//新结点左子树为最小结点 
		
		tree[k].rightchild = node2;//新结点右子树为次小结点 
	}
}

void form_code(huffmannode tree[],int n)//生成哈夫曼编码 
{
	int cur, parent, start;
	
	string huffcode;
	
	for(int i=0;i<n;++i)//遍历n个输入的结点 
	{
		cur = i;
		
		parent = tree[i].parent;
		
		while(parent!=-1)//当没有到达根结点,向上寻找父结点 
		{
			if(tree[parent].leftchild==cur)//如果当前结点是左子树 
			{
				huffcode = '0' + huffcode;//在哈夫曼编码前加0 
			}
			else
			{
				huffcode = '1' + huffcode;//加1 
			}
			
			cur = parent;//更新当前结点 
			
			parent = tree[parent].parent;//更新父结点 
		}
		
		code[tree[i].weight] = huffcode;//将生成的哈夫曼编码用map保存 
		
		translate[huffcode] = ch[i];//将哈夫曼编码对应的值保存 
		
		huffcode.clear();//清空哈夫曼编码 
	}
}

void print_code(huffmannode tree[],int n)//输出 
{
	cout << "得到的哈夫曼值为" << endl;
	
	for(int i=0;i<n;++i)
	{
		cout << ch[i] << ":" << tree[i].weight << "的哈夫曼值为" << code[tree[i].weight] << endl;
	}
}

void translate_code(string unknown)//翻译编码 
{
	string s;
	
	for(int i=0;i<unknown.size();++i)//读入未知编码 
	{
		s = s + unknown[i];
		
		if(translate[s]!=0)//已读入部分成功匹配现有编码 
		{
			cout << translate[s];//输出对应值 
			
			s.clear();//清空已读入部分 
		}
	}
	
	cout << endl;
}

void translate_string(string unknown)//编码字符串 
{	
	for(int i=0;i<unknown.size();++i)//读入未知编码 
	{
		cout << code[alp[unknown[i]]];
	}
	
	cout << endl;
}

int main()
{
	int n;
	
	cout << "请输入结点的数量(解码过程)" << endl;
	
	cin >> n; 
	
	cout << "请输入结点各自的字符和值" << endl;
	
	for(int i=0;i<n;++i)
	{
		cin >> ch[i];
		
		cin >> w[i];
		
		alp[ch[i]] = w[i];
	}
	
	huffmannode *tree = new huffmannode[2*n-1];
	
	creat_tree(tree,w,n);
	
	form_code(tree,n);
	
	print_code(tree,n);
	
	string unknown;
	
	cout << "请输入一段待翻译的01字符串(译码过程)" << endl; 
	
	cin >> unknown;
	
	cout << "翻译结果为"  << endl; 
	
	translate_code(unknown);
	
	cout << "请输入一段字符串(编码过程)" <<endl;
	
	cin >> unknown;
	
	cout << "转码结果为" << endl; 
	
	translate_string(unknown);
	
	return 0;	
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值