算法基础(八):超详细最优二叉树构建(1)

赫夫曼(Huffman)树也称最有二叉树,是一类带全路径长度最短的树,有着广泛的应用。比如一棵判定树,根据学生的成绩划分及格还是不及格还是优、中等、良好。显然用if-else或者switch就可以简单实现,当然可以直接毫不考虑的直接这样写,但是如果我们再肯花点功夫,就可以得到更加高效的程序。我们可以以学生的总的学科分数的占的各个分数段的比率为权,构造一棵赫夫曼树,这样可以减少比较次数,提高程序运行效率。

构造赫夫曼树的方法步骤其实很简单--赫夫曼算法:

(1).
根据给定的n个权值{w1,w2,w3...,wn}构成n棵二叉树的集合F = {T1,T2,....Tn},其中每棵二叉树Ti中只有一个带权的wi的根节点,其左右子树为空。

(2).
在F中选取两棵根节点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根节点的权值为其左、右子树上根节点的权值之和。

(3).
在F中删除这两棵树,同时将新得到的二叉树加入到F中。

(4).
重复(2)、(3),知道F中含一棵树为止。

下面是构造HuffmanTree的代码实现:

#include"stdafx.h"
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>

typedef struct
{
	unsigned int weight;
	unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;		//动态分配数组,存储哈弗曼树
typedef char** HuffmanCode;	//动态分配数组存储哈夫曼编码表

void MaoPao(HuffmanTree HT,int* arr,int number,int &s1,int &s2)	//传入HT、数组首地址、数组中元素的个数:m
{
	//只需进行两趟比较即可,得到两个最小数
	int i,j,m;
	printf("\n进入冒泡排序函数...");
	for(i = 0;i<2;i++)
	{
		for(j = 0;j<number - i;j++)	//number是数组中的实际元素个数..
		{
		//	printf("\n进入循环");
			//printf("\n arrj = %d,arrj+1 = %d",arr[j],arr[j+1]);
		if(HT[ arr[j] ].weight < HT[ arr[j+1] ].weight)
			{
				m = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = m;
			}
		}
	}
	s1 = arr[number - 1];
	s2 = arr[number];
	printf("\n.........%d,%d",s1,s2);
}
void Select(HuffmanTree HT,int n,int &s1,int &s2)	//n是总的节点数量
{
	printf("\n进入Select函数");
	int arr[20] = {0};	//存放parent为0的节点的编号
	int m = 0;
	for(int i = 1;i<=n;i++)
	{
		if(HT[i].parent == 0)
		{
			arr[m] = i;	//从0开始存,那么数组中的元素个数就 = m
			m++;
			printf("\nparent = 0的节点号:%d",i);
			if(m > 19)m = 19;
		}
	}
	//比如n = 8,表示一共8个数,最后m++ = 8。实际数组是0~7的,那么m就是数组中的元素个数
	//OK,找到parent = 0 的节点,下面选择weight最小的两个,该用什么算法呢?我用的是冒泡法,上浮两个最小数
	MaoPao(HT,arr,m,s1,s2);	//m是数组中的元素个数..数组从1开始,数组中的最后一个元素是m,倒数一个是m-1得到两个权值最小的节点

}

int HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int* w,int n)	//n是叶子的数量,w存放n个字符(叶子)的权值
{
	int m;			//总共的节点数
	int s1 = 0;
	int s2 = 0;		//存储选择到的节点编号
	char* cd;
	int c;
	int f;
	int start;
	HuffmanTree  p;
	int i = 0;
	if(n <= 1)
		return 0;
	m = 2 * n - 1;

	HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));

	for(p = HT+1,i = 1;i <= n; ++i,++p,++w)//第一号单元空出来的,从1开始,这里是初始化操作,分两步,一步是有权值的,已不是没有权值的!用if也是可以的
	{
		p->weight = *w;
		p->parent = 0;
		p->lchild = 0;
		p->rchild = 0;
	}
	for(;i <= m;++i,++p)
	{
		printf("a..aaaaaaa......i = %d",i);
		p->weight = 0;
		p->parent = 0;
		p->lchild = 0;
		p->rchild = 0;
	}
	printf("初始化完毕..");
	//建立哈弗曼树
	//8,这是后面测试的。
	for(i = n+1;i<=m;++i)		//这里要循环n-1次,也就是说,构造哈弗曼树需要同一个操作做n-1次,m = 2n-1,2n-1-(n+1)+1 = n-1
	{
		Select(HT,i-1,s1,s2);
		printf("\n此时...i = %d,m = %d,,,被选中的编号..%d,%d",i,m,s1,s2);
		HT[s1].parent = i;  HT[s2].parent = i;
		HT[i].lchild = s1;  HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}
	return 1;

}

void ShowHT(HuffmanTree &HT,int n)	//n是叶子的数量
{

	int m = 2*n - 1;	//总共的节点数量
	for(int i = 1;i<=m;i++)
	{
		printf("\n编号:%d--Weight:%d  Parent: %d  LeftChild: %d  RightChild;%d",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
	}
}

下面是main函数的测试:

#include"stdafx.h"
//#include"BasicGraph2.h"
#include "HuffmanCode.h"
void main()
{
	HuffmanTree HT;
	HuffmanCode ch;
	int n = 8;
	int m = 15;
	int arr[] = {5,29,7,8,14,23,3,11};
	if(HuffmanCoding(HT,ch,arr,n))
		ShowHT(HT,n);
}

运行结果:

图2:

说明:其实根据上面的权值,树有多种,但是WPL都是一样的。

时间: 2024-11-05 20:37:10

算法基础(八):超详细最优二叉树构建(1)的相关文章

算法基础(九):超详细最优二叉树构建(2)求编码

从叶子到跟逆向求每个字符的赫夫曼编码: void GetHuffmanCode(HuffmanTree &HT,HuffmanCode &HC,int n) { char* cd; int c; int f; int start; int i = 0; //从叶子到根逆向求每个字符的哈夫曼编码 printf("\n进入求编码函数..."); HC = (HuffmanCode)malloc( (n+1) * sizeof(char*)); //分配n个字符编码的头指针向

【智能算法】粒子群算法(Particle Swarm Optimization)超详细解析+入门代码实例讲解

喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 算法起源 粒子群优化算法(PSO)是一种进化计算技术(evolutionary computation),1995 年由Eberhart 博士和kennedy 博士提出,源于对鸟群捕食的行为研究 .该算法最初是受到飞鸟集群活动的规律性启发,进而利用群体智能建立的一个简化模型.粒子群算法在对动物集群活动行为观察基础上,利用群体中的个体对信息的共享使整个群体的运动在问题求解空间中产生从无序到有序的演化过程,从而获得最优解.

javascript实现数据结构: 树和二叉树的应用--最优二叉树(赫夫曼树),回溯法与树的遍历--求集合幂集及八皇后问题

赫夫曼树及其应用 赫夫曼(Huffman)树又称最优树,是一类带权路径长度最短的树,有着广泛的应用. 最优二叉树(Huffman树) 1 基本概念 ① 结点路径:从树中一个结点到另一个结点的之间的分支构成这两个结点之间的路径. ② 路径长度:结点路径上的分支数目称为路径长度. ③ 树的路径长度:从树根到每一个结点的路径长度之和. 以下图为例: A到F :结点路径 AEF : 路径长度(即边的数目) 2 : 树的路径长度:3*1+5*2+2*3=19: ④ 结点的带权路径长度:从该结点的到树的根结

哈夫曼树(最优二叉树)及哈夫曼算法

哈夫曼树 在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN)树和哈夫曼编码.哈夫曼编码是哈夫曼树的一个应用.哈夫曼编码应用广泛,如JPEG中就应用了哈夫曼编码. 首先介绍什么是哈夫曼树.哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树.所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数).树的带权路径长度记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权

算法核心——空间复杂度和时间复杂度超详细解析

算法核心——空间复杂度和时间复杂度超详细解析 一.什么是算法 算法: 一个有限指令集 接受一些输入(有些情况下不需要收入) 产生输出 一定在有限步骤之后终止 每一条指令必须: 有充分明确的目标,不可以有歧义 计算机能处理的范围之内 描述应不依赖于任何一种计算机语言以及具体的实现手段 其实说白了,算法就是一个计算过程解决问题的方法.我们现在已经知道数据结构表示数据是怎么存储的,而“程序=数据结构+算法”,数据结构是静态的,算法是动态的,它们加起来就是程序. 对算法来说有输入,有输出,相当于函数有参

【算法设计与分析基础】22、最优二叉查找树

package cn.xf.algorithm.ch08DynamicProgramming; import java.util.Arrays; import org.junit.Test; import cn.xf.algorithm.ch08DynamicProgramming.vo.ResultVo; /** * 最优二叉树问题 * * 思路:根据最优二叉树的问题就是查找对应的节点的比较次数的期望值保持最小 * 最优二叉查找树的期望搜索代价保持最小 * 例如:一颗树有节点{k0,k1,k2

linux内存基础知识和相关调优方案

内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁.计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大.内存作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据.只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行.对于整个操作系统来说,内存可能是最麻烦的的设备.而其性能的好坏直接影响着整个操作系统. 我们知道CPU是不能与硬盘打交道的,只有数据被载入到内存中才可

超强、超详细Redis数据库入门教程

这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么2.redis的作者何许人也3.谁在使用redis4.学会安装redis5.学会启动redis6.使用redis客户端7.redis数据结构 – 简介8.redis数据结构 – strings9.redis数据结构 – lists10.redis数据结构 – 集合11.redis数据结构 – 有序集合12.redis数据结构 – 哈希13.聊聊

JAVA算法基础-贪心算法

前言 学无止境.算法博大精深啊,一个贪心算法里面就隐含了这么多不同的场景实现,每个场景下的算法就有多种不同的实现,个人写法不一也成就了各种不同的漂亮算法,看了这些实现,也让我开拓了思维,这个世界的方案永远没有最完美的只有最合适的- ! 1.贪心算法概念 贪心算法也叫贪婪算法,当然叫法随意.主要目的是在问题求解时,做出最正确的判断= =,这不是贪心是啥?在计算机工程领域当中,就是说不考虑整体最优算法而是从局部做到最优解.当然贪心是算法不能对所有的问题都能得到整体都最优解,但对多数个问题还是能得到近