哈夫曼树的构造及C++代码实现

这篇具有很好参考价值的文章主要介绍了哈夫曼树的构造及C++代码实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

哈夫曼树的构造过程:

(1) 以权值分别为W1,W2...Wn的n各结点,构成n棵二叉树T1,T2,...Tn并组成森林F={T1,T2,...Tn},其中每棵二叉树 Ti仅有一个权值为 Wi的根结点;

(2) 在F中选取两棵根结点权值最小的树作为左右子树构造一棵新二叉树,并且置新二叉树根结点权值为左右子树上根结点的权值之和(根结点的权值=左右孩子权值之和,叶结点的权值= Wi)

(3) 从F中删除这两棵二叉树,同时将新二叉树加入到F中;

(4) 重复(2)、(3)直到F中只含一棵二叉树为止,这棵二叉树就是Huffman树。

参考《数据结构(C语言版)(第二版)》(严蔚敏编)第138页)

哈夫曼树存储结构:

一棵有n个叶子结点的哈夫曼树共有2n-1个结点,可以将其存于一个大小为2n-1的数组中,为了方便(第i个结点用下标为i表示),所以将数组0号单元置空,故数组的大小为2n。哈夫曼树对于一个结点来说需要存储其权值、双亲及左右孩子,因此哈夫曼树的存储表示如下:

typedef struct {
    //定义一个结构体数组
    int weight;//权重
    int p, lc, rc;//结点双亲及左右孩子下标
}*HuffmanTree,HTNode;

将叶子结点集中存储在1~n的位置,后面的n-1个位置存储非叶子结点。

哈夫曼树构造的算法实现:

构造huffmantree大致分为两大步骤:

1.初始化

2.创建树

严蔚敏版的《数据结构(c语言版)(第二版)》对其算法描述如下:

void CreateHuffmanTree(HuffmanTree &T, int n){
//初始化


    if(n <= 1) return;
    m = 2*n-1;
    T = new HTNode[m+1];//0号单元未用,动态分配m+1个单元
    for(1 = 1;i <= m;i++){
        T[i].p = 0;
        T[i].lc = 0;
        T[i].rc = 0;
    }
    for(i = 1;i <= n;i++){
        cin>>T[i].weight  //依次输入前n个叶子结点的权值
    }


/*----------------初始化结束,下面开始创建哈夫曼树--------------------*/


    for(i = n+1;i <= m;i++){
    //n个叶子结点,2n-1个结点,共要n-1次合并产生n-1个新的结点


    Select(T,i-1,s1,s2);
    //在T[k]中 (k范围为[1,i-1])找到两个权值最小且双亲域为0的结点,返回它们在T中的序号s1,s2
    T[s1].p = i; T[s2].p = i; //得到新结点i,从森林中删除s1、s2,将s1、s2的双亲域改为i
    T[i].lc = s1; T[i].rc = s2; //s1、s2分别作为i的左右孩子
    T[i].weight = T[s1].weight + T[s2].weight; //i的权值为左右孩子之和

    }

}

具体实现的时候,除了一些初始化和语法规范,主要的是写出select函数,由于刚刚开始学,自身代码水平不行笔者在写select函数的时候遇到了不少麻烦。

要找权值最小的两个下标可以如下实现:

int min1 = 100;
int min2 = 100;

 //定义min1,min2分别为最小值和次小值,赋一个很大的值(至少比叶子结点最大的权重要大)这里以100为例子
for (int j = 1;j <= i - 1;j++) {
        if (T[j].p == 0) {
        //条件为双亲域为0
            if (T[j].weight < min1) {
                min2 = min1;   
                min1 = T[j].weight;
               //如果第j个结点的权重比最小值小,min2更新为min1,min1更新为第j个结点的权重

            }
            else if (T[j].weight <= min2) {
                min2 = T[j].weight;
                //如果第j个结点的权重比次小值min2还小,那min2更新为该值
            }
            
        }
    }
   

//上述循环中找到两个最小值,但要求的是两个下标,故再次循环找
    for (int j = 1;j <= i - 1;j++) {
        if (T[j].p == 0 && T[j].weight == min1) {
            s1 = j;
  //这里要注意不要忘记双亲域为0的条件,如果已经合并过的结点(双亲域不为0)的权值恰好等于这一次合并的最小值,就会出错
        }
    }
    for (int j = 1;j <= i - 1;j++){
        if (T[j].p == 0 && T[j].weight == min2 && j != s1) {
            s2 = j;
            //这里还得添加一个条件,也就是s1!=s2
            //如果min1 = min2,但此时j1!=j2,也就是下标不同,如果不加该条件的话s1和s2的值相同,也就是只找到了一个值,也会报错
        }

如果像算法描述的那样,s1、s2作为select的参数很难定义和初始化,因此不如将:

    T[s1].p = i;
    T[s2].p = i;
    T[i].lc = s1;
    T[i].rc = s2;
    T[i].weight = T[s1].weight + T[s2].weight;

这一段放到select函数里实现,再将i作为参数传到select函数中就会方便许多。

完整代码实现:

测试的以书上的例题w = {5,29,7,8,14,23,3,11} 为例,n = 8,m = 15

测试第14、15个结点的权值、双亲及左右孩子的结点(因为一开始逐步调试的时候这两个结点的错误最多)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<Windows.h>
#include<malloc.h>

typedef struct {
	//定义一个结构体数组
	int weight;//权重
	int p, lc, rc;//结点双亲及左右孩子下标
}*HuffmanTree,HTNode;

void select(HuffmanTree& T, int n, int i) {
	//找T中下标范围1----i-1且双亲域为0的权重最小的两个结点下标为s1,s2
	int min1 = 100;
	int min2 = 100;
	int s1 = 0;
	int s2 = 0;
	for (int j = 1;j <= i - 1;j++) {
		if (T[j].p == 0) {
			if (T[j].weight < min1) {
				min2 = min1;
				min1 = T[j].weight;
			}
			else if (T[j].weight <= min2) {
				min2 = T[j].weight;
			}
			
		}
	}
	for (int j = 1;j <= i - 1;j++) {
		if (T[j].p == 0 && T[j].weight == min1) {
			s1 = j;
		}
	}
	for (int j = 1;j <= i - 1;j++){
		if (T[j].p == 0 && T[j].weight == min2 && j != s1) {
			s2 = j;
		}
		
	}
	T[s1].p = i;
	T[s2].p = i;
	T[i].lc = s1;
	T[i].rc = s2;
	
	T[i].weight = T[s1].weight + T[s2].weight;
	
}
void CreateHuffmanTree(HuffmanTree& T, int n) {
	if (n <= 1) {
		return;
	}
	int m = 2 * n - 1;
	
	//1.初始化数组
	T = new HTNode[m + 1];
	for (int i = 1;i <= m;i++) {
		T[i].p = 0;
		T[i].lc = 0;
		T[i].rc = 0;
	}
	for (int i = 1;i <= n;i++) {
		printf("第%d个结点权重为:\n", i);
		scanf("%d", &(T[i].weight));
	}
	//2.创建哈夫曼树
	for (int i = n + 1;i <= m;i++) {
		//n-1次合并,n-1次循环
		
		select(T, n, i);
		//找T中下标范围1----i-1且双亲域为0的权重最小的两个结点

	}


}


int main() {
	HuffmanTree T;
	//测试用w = {5,29,7,8,14,23,3,11}
	CreateHuffmanTree(T, 8);
	printf("%第十四个结点的权重为%d,双亲为%d结点,左孩子为%d结点,右孩子为%d结点\n", T[14].weight,T[14].p,T[14].lc,T[14].rc);//测试用数据
	printf("第十五个结点的权重为%d,双亲为%d结点,左孩子为%d结点,右孩子为%d结点\n", T[15].weight,T[15].p,T[15].lc,T[15].rc);
	system("pause");
}

测试结果如下:

哈夫曼树的构造及C++代码实现

 ps:笔者第一次写博客,若有代码错误和表述不清还请见谅,谢谢!!!!!!!!!!文章来源地址https://www.toymoban.com/news/detail-451834.html

到了这里,关于哈夫曼树的构造及C++代码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 构造哈夫曼树(数据结构实训)(难度系数85)

    构造哈夫曼树 题目描述: 根据给定的叶结点字符及其对应的权值创建哈夫曼树。 输入: 第一行为叶子结点的数目n(1=n=100)。第二行为一个字符串,包含n个字符,每个字符对应一个叶子结点,第三行为每个叶子结点的概率(即权值),要求根据各叶结点构造哈夫曼树。构造哈

    2024年02月03日
    浏览(33)
  • 哈夫曼树编码的实现+图解(含全部代码)

    目录 哈夫曼树的基本概念 ------------哈夫曼树的构造方法  ------------------------哈夫曼编码 ------------------------------------全部代码           哈夫曼树 通常以二叉树的形式出现,所以也称最优二叉树,是一类带权路径长度最短的树 首先得知道下以下几个术语:         

    2024年02月03日
    浏览(75)
  • 哈夫曼树的构建(详解顺序结构和链式结构)

    关于树的一些基本知识这里就不再提了,如果不知道的小伙伴可以先去了解一下,我们直接进入正题。哈夫曼树是一种特殊的树。根据定义: 哈夫曼树 ,又叫做 最优树 ,是一种 带权路径长度最小 的树。哈夫曼树中没有度为1的节点(哈夫曼树也是二叉树),因此包含n个结

    2024年02月05日
    浏览(46)
  • c++利用哈夫曼编码实现文件的压缩加密和解压缩解密

    需求分析 @1:编码实现哈夫曼树,然后根据数据建立哈夫曼树,然后显示所有的字符的哈夫曼编码 @2:实现哈夫曼编码和解码 并通过编码实现文本文件的压缩 通过解码实现压缩文件的解压缩 概要设计 @1:在二叉树的基础上实现哈夫曼树的数据结构 @2:读取文本文件--对字符频

    2024年02月03日
    浏览(43)
  • 数据结构课程设计——哈夫曼编/译码系统设计与实现(C++)

    对于生产实际的问题,本设计可以作为一个无损数据压缩工具,在需要传输海量数据时,利用哈夫曼编码可以将数据进行压缩,从而减小传输的数据量,提高数据传输效率。同时,哈夫曼编码也可以应用于数据加密和解密等领域。 本设计的主要目的是学习哈夫曼编码算法,并

    2024年02月04日
    浏览(50)
  • 数据结构“基于哈夫曼树的数据压缩算法”的实验报告

    一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com Last edited: 2022.11.20 目录 数据结构“基于哈夫曼树的数据压缩算法”的实验报告 一、实验目的 二、实验设备 三、实验内容 1.【问题描述】 2.【输入要求】 3.【输出要求】 4.【实验提示】 四、实验步骤

    2024年02月09日
    浏览(62)
  • 实现哈夫曼编码(C语言)

    编译环境:Dev-C++ 实现哈夫曼编码的贪心算法实现,并分析哈夫曼编码的算法复杂度。         该题目求最小编码长度,即求最优解的问题,可分成几个步骤,一般来说, 每个步骤的最优解不一定是整个问题的最优解,然而对于有些问题,局部贪心可以得到全局的最优解

    2023年04月20日
    浏览(39)
  • C语言---数据结构实验---哈夫曼树及哈夫曼编码的算法实现---图的基本操作

    本篇实验代码非本人写,代码源自外部,经调试解决了部分warning和error后在本地vs上可以正常运行,如有运行失败可换至vs 未来会重构实现该两个实验 内容要求: 1、初始化(Init):能够对输入的任意长度的字符串s进行统计,统计每个字符的频度,并建立哈夫曼树 2、建立编码

    2024年02月13日
    浏览(59)
  • 哈夫曼树介绍及Java实现

    哈夫曼树-最优二叉树:树的带权路径长度最小的二叉树; 权值均为叶子结点; 权值越大,结点距离根节点越近; 对权值序列进行升序排列,选出其中最小的两个权值进行合并; 将合并结点加入权值序列,重新进行排序; 重复执行上述两个操作,直到序列中只剩一个节点即

    2024年02月12日
    浏览(31)
  • (数据结构)哈夫曼编码实现(C语言)

    哈夫曼的编码:从一堆数组当中取出来最小的两个值,按照左下右大的进行绘制,将两个权值之和,放入队列当中,然后再进行取出两个小的,以此类推,直到全部结束,在根据图根节点,到叶子节点,每一个分支来得出编码,向左0,向右1,即可得到一个结果。

    2024年02月16日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包