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

2023-11-01

引言

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

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

假设有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)自然而然就是最优了。

案例实现

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

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

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

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

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

 

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

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<min)
			{
				min = T[i].weigth+T[j].weigth;
				*index1 = i;
				*index2 = j;
			}
			}
		}
	}
	//返回权值最小的两个值的索引
}

因为想了半天都只用基于时间复杂度在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<min)
			{
				min = T[i].weigth+T[j].weigth;
				*index1 = i;
				*index2 = j;
			}
			}
		}
	}
	//返回权值最小的两个值的索引
}
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);
		
	}
}
void test(int data[],int * x1,int * x2){
	int min=data[1]+data[2];
	int index1,index2;
	for (int i = 0; i < 6; i++)
	{
		for (int j = 0; j < 6; j++)
		{
			if(data[i]+data[j]<min&&i!=j)
			{
				min = data[i]+data[j]; //重新为max赋值
				*x1 = i;
				*x2 = j; //重新为index1,index2 赋值
			}
		}
	}
	
}
int _tmain(int argc, _TCHAR* argv[])
{
	Huffman HT;
	int n = 6;
	CreateHuffman(&HT,n);


	return 0;
}

  

 

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • Es java分页查询列表数据

    Autowired private RestHighLevelClient client public List
  • Android 计算View的深度

    这次遇到一个需求 需要计算当前View的深度 基本上就是大学时候数据结构里求二叉树的解法 记录一下 理论上也可以用于性能优化和性能监控 private int maxDeep View view view不会有子view所以就返回0 if
  • 4.2 线性方程组有解判断

    文章目录 系数矩阵 增广系数矩阵 方程组的矩阵与向量表示形式 结论 判断方程组有无解的步骤 求线性方程组的一般思路 例题 参考 系数矩阵 增广系数矩阵 方程组的矩阵与向量表示形式 求解方程组就是对增广矩阵做初等行变换将系数矩阵化为行简化阶梯
  • Python——算法

    文章目录 算法 1 世界末日 2 马虎的算式 3 振兴中华 4 斐波那契数列 5 武功秘籍 6 切面条 7 立方变自身 8 圆的面积 9 字母图形 10 Huffuman树 算法 1 世界末日 曾有邪教称1999年12月31日是世界末日 当
  • 游戏开发unity插件DoTween:实现人物向目标方向旋转

    已知世界坐标下目标对象的朝向向量B 当前人物朝向向量A transform forward 如何用DoTween实现人物旋转动画呢 Vector3 forwardWorldVector B float duration 0 5f trans
  • 产品研发流程

    需求管理流程介绍 1 1需求管理流程 产品研发的生命周期 一般需要以下几个环节 1 2常用的调研方法 1 3如何进行访谈 访谈注意事项 1 列调研大纲 根据大纲去调研 2 调研顺序 先流程后细节 1 流程从哪里开始 由谁发起 什么事情触发的
  • 想入手抖音定制生日祝福短视频,没有创意思路怎么办?几个方面带你了解整个流程

    项目 定制派大星生日祝福视频 原理 从抖音引流到微信转为私域流量 成本 一部手机 一个微信小号 需要的资源 配音声优 视频素材 一个抖音号 剪辑工具 剪映 这是一个淘宝商品改造成抖音的玩法项目 一 需求思路 儿童喜欢看的动画片人物 比如 派
  • ubuntu16.04开起wifi热点

    1 首先保证电脑连接有线网络 2 点击电脑屏幕右上方联网图标 选择最后一个选项 编辑连接 3 进入如下页面 选中选中wifi选项 点击添加 4 进入如下页面 选择连接类型为wifi 点击新建 5 进入如下页面 填写连接名称与SSID 这两项
  • java深度克隆工具类——支持对象和对象集合

    正经学徒 佛系记录 不搞事情 第一步 创建工具类 直接使用commons beanutils实现对象拷贝 引入pom
  • mysql数据库存储逻辑_MySQL逻辑架构及存储引擎简介

    MySQL逻辑架构 并发控制 由锁实现 读锁 也叫共享锁 读锁互相不阻塞 A加锁表后A b c d都能读该表但不能写该表 写锁 也叫排他锁 写锁相互阻塞 A加排他锁后 其他线程不能读写该表 锁粒度 表锁 锁一个表 并发粒度小 代表存储引擎M
  • Blazor 模板化组件开发指南

    翻译自 Waqas Anwar 2021年4月15日的文章 A Developer s Guide To Blazor Templated Components 1 在我之前的一篇文章 Blazor 组件入门指南中 我介绍了组件参数 并向您
  • javascript 转数字:javascript数字相加

    var a 3 var b 98 c a b 想得到c 101 确变成了字符串拼接 得到了398 我该则么做呢 c parseInt a parseInt b
  • #pragma once 与 #ifndef

    在C C 中 使用 include 包含文件的时候 经常使用方法去防止重复引用 产生二义性 通常有两种方式 第一种 ifndef指令方式代码被重复引用 比如说 ifndef CODE BLOCK define CODE BLOCK code
  • 谈文本分类

    本文来自对 文本分类研究综述 汪岿的阅读 文章目录 1 为什么要进行文本分类 2 文本分类的分类 应用 3 当前文本分类面临的挑战 4 文本分类的前景 1 为什么要进行文本分类 在大数据时代 网络上的文本数据日益增长 采用文本分类技术对海量
  • 04-Java框架-MyBatis

    一 MyBatis的介绍 1 1 回顾一下JDBC 下面这个代码是使用JDBC实现基于id查询员工信息 我们来分析分析有什么弊端 public Employee selectById Long id Connection conn null
  • 【解决】pytorch单机多卡问题:ERROR: torch.distributed.elastic.multiprocessing.api:failed

    最近在使用单机多卡进行分布式 DDP 训练时遇到一个错误 ERROR torch distributed elastic multiprocessing api failed 而实际报错的内容是 ValueError sampler opt
  • LeetCode·每日一题·722. 删除注释·模拟

    题目 示例 思路 题意 gt 给定一段代码 将代码中的注释删除并返回 由于注释只有两种类型 字符串 表示行注释 表示 和其右侧的其余字符应该被忽略 字符串 表示一个块注释 它表示直到下一个 非重叠 出现的 之间的所有字符都应该被忽略 阅读顺
  • Vuforia AR学习

    传送门 1 搜索 Vuforia 下载相关 SDK 和 Samples 2 这个就有点坑了 想运行 sample demo 需要把下载好的sample拷贝至sdk目录下的sample文件夹下 如图 3 也可以修改修改 Samples dem
  • Linux中nginx配置ssl证书实现https访问(nginx-1.16.1为例)

    配置ssl证书之前 先准备好SSL证书 至于获取的途径很多 不清楚的可以自行搜索 也可以留言 准备好证书后 找到nginx的安装目录 我的安装位置为 usr local nginx 1 16 1 进入 conf nginx conf 编辑n
  • 数据结构:哈夫曼树算法(内含Select函数算法解析)全网最全解释

    引言 学习数据结构的都应该清楚 哈夫曼树是书章节的最后一个内容 也是相对重要的一个知识 他可以应用在生活的各个例子中 如下图所示 假设有ABCD 四个货物架D货架物品被人购买的概率是20 C货架是 35 B货架是 60 D货架是80 那么显