数据结构:哈夫曼树算法(内含Select函数算法解析)全网最全解释

引言

学习数据结构的都应该清楚,哈夫曼树是书章节的最后一个内容,也是相对重要的一个知识

他可以应用在生活的各个例子中,如下图所示

数据结构:哈夫曼树算法(内含Select函数算法解析)全网最全解释_第1张图片

假设有ABCD 四个货物架D货架物品被人购买的概率是20% C货架是 35% B货架是 60% D货架是80% 那么显然,人们更倾向于去购买A货架的物品 但A又是最远的 每次访问A货架都要经过           D->C->B 才能到A 其次是B,那么有没有什么方法能减少访问A的路径让消费者更省力呢。

 思考

那么这里就要介绍一种新的数据结构,哈夫曼树(Huffman),那么哈夫曼树中的一些特性我们也必须要先认识下

路径:也就是如上图人们从货架D到货架A的距离称为路径

路径长度:如上图D到A如果相隔100m,那么路径长度就是100,因为这里是哈夫曼树,算一个节点到另一个节点的总分支数

权:赋予某个节点的值,可以理解为上面货架被访问的概率

路径带权长度:就是类似货架D到货架A的路径总长度和权的乘积

那么如何优化上面顾客的体验呢,就是让货架A能够更近的被顾客访问到呢?

这里就要拓展树的带权路径长度长度(WPL)

也就是所有节点的带权路径总和,简单来说,让访问概率较多的货架都往前挪嘛。这样概率高的货架访问路劲都缩短了 总的路权路径总和(WPL)自然而然就是最优了。

案例实现

现在,这几个货架变成几个冰冷的数字,如下

数据结构:哈夫曼树算法(内含Select函数算法解析)全网最全解释_第2张图片

 那么哈夫曼的主要核心思想:选取权值最小的两个节点合并为一个新节点,新节点的权值为两个节点的权值的和,将两个该两个节点设置双亲域下次不再访问,将新节点引入,并且设置其左孩子和右孩子为这两个节点。

创建完哈夫曼树如下图所示,权值写在圈内的就是原本的节点,圈外的就是新产生的节点

数据结构:哈夫曼树算法(内含Select函数算法解析)全网最全解释_第3张图片

 所以可以不难推出,n个节点可以得出n-1个新节点那么一个哈夫曼树就有2n-1个节点。 得到这个结论那么我们就可以把整个哈夫曼数节点关系保存在一个数组中,那么这个数组总共需要2n-1的空间大小对吧。

这里先上代码实现,这里的双亲以及孩子都是代表节点的索引值,因为存在数组中,只要给索引就可以标识了

数据结构:哈夫曼树算法(内含Select函数算法解析)全网最全解释_第4张图片

 

那么得到这个结论我们就直接进入主要实现函数

void CreateHuffman(PHuffman T,int n)  //T要创建的hafuman树 n:总节点个数
{
	if(n<=1)
		return;
	int m = 2*n-1; //设置总节点个数
	T = new Huffman[m+1]; //因为[2*n-1]是从0~2n-2的范围 0位置不用 直接从1开始 所以m+1
	for(int i = 1;i<=m;i++)//初始化哈夫曼节点 让每个节点的双亲值 左孩子右孩子均置为0
	{
		T[i].lchild = 0;
		T[i].rchild = T[i].lchild;
		T[i].parent = 0;
	}
	//哈夫曼树初始化完毕
	//为每个哈夫曼节点设置权值
	int weigth;
	printf("输入权值\n");
	for (int i = 1; i <=n; i++)
	{
		scanf_s("%d",&weigth);
		T[i].weigth = weigth;
	}
	//全职设置完毕,现在需要遍历该哈夫曼树找到最小和其次小的两个节点返回
	for (int i = n+1; i <= m; i++)
	{
		int s1,s2;
		Select(T,i-1,&s1,&s2);
		T[s1].parent = i;T[s2].parent = i;
		T[i].lchild = s1;T[i].rchild =s2;
		T[i].weigth = T[s1].weigth+T[s2].weigth;
	}
		for (int i = 1; i <= m; i++)
	{
		printf("节点 %d 权值为 :%d 双亲为:%d 左孩子为 :%d 右孩子为:%d \n",i,T[i].weigth,T[i].parent,T[i].lchild,T[i].rchild);
		
	}
}

上面代码都有注释,因为书上没有给出Select()实现代码,我这边自己写了一个如下

void Select(PHuffman T,int flag,int * index1,int * index2) 
{
	//传入哈夫曼数组,从1<=x<=flag的位置找到parent为0,且权值最小的两个节点
	int min = 1000;
	for (int i = 1; i <=flag; i++)
	{
		for (int j = 1; j < flag; j++)
		{

			if (T[i].parent==0&&T[j].parent==0&&i!=j)
			{
			if(T[i].weigth+T[j].weigth

因为想了半天都只用基于时间复杂度在O(n^2)的基础下实现选择最小的两个数的算法,有佬有更优算法也可以评论区指教下谢啦。

这里给出全部代码

// ConsoleApplication17.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdlib.h"

typedef struct Huffman
{
	int weigth; //权值
	int parent,lchild,rchild;
}Huffman,*PHuffman;
//设置n个根节点 由n个根节点可以生成n-1个新的节点 所以共有2n-1个节
void Select(PHuffman T,int flag,int * index1,int * index2) 
{
	//传入哈夫曼数组,从1<=x<=flag的位置找到parent为0,且权值最小的两个节点
	int min = 1000;
	for (int i = 1; i <=flag; i++)
	{
		for (int j = 1; j < flag; j++)
		{

			if (T[i].parent==0&&T[j].parent==0&&i!=j)
			{
			if(T[i].weigth+T[j].weigth

数据结构:哈夫曼树算法(内含Select函数算法解析)全网最全解释_第5张图片

 

以上就是哈夫曼的实现过程,有什么疑问评论区留言,看到都会回复。

你可能感兴趣的:(算法,数据结构,霍夫曼树)