哈夫曼树-最优二叉树

# 定义

 

1. 路径:结点中一个结点到另一个结点的通路(线)叫做路径

2. 路径长度:结点到另一个结点,线的累加和

3. 权:结点带有的数值

4. 带权路径长度:权×路径长度

最优二叉树指的是带权路径长度最短的树

 

 

如果有带权的结点 A(12)B(5) C(6)

# 如何构成哈夫曼树(带权路径长度最短的树)

其实只要满足一个条件,将权大的放到靠近根结点的位置(因为哈夫曼树是带权路径长度最短的树,带权路径长度为权*路径长度,将权大的靠近根节点,使路径长度变短)

## 构建哈夫曼树的公式:

1. 选择两个较小的结点                        这里面选择B(5) C(6)

2. 将两个小的结点构造成树 (增加父母结点,并给父母结点赋权)             

3. 将父母结点作为 结点加入到初始结点的队列当中去

 

 4. 重复步骤 1(选择较小结点)        这里面选择 A(12) 空(11)

5. 构成新结点,此时没有剩余结点,就算创建完毕

#定义数据结构

1. 结点

typedef struct {
    int parent;    //父母结点的下标
    int weight;    //结点的权
    int lchild;    //左孩子的下标
    int rchild;    //右孩子的下标
}HTNode,*HuffmanTree;

2. 定义

int n 初始结点的个数

int s1 最小的结点

int s2 第二小的结点

int m=2*n 哈夫曼数组的大小,注意原本应该是2n-1个,但是在这个数组中,我们统一不用下标为0的结点

构建一颗哈夫曼树需要2*n-1个结点(通过观察)

void CreathuffmanTree(HuffmanTree &HT, int n) {
	int i;
	int m = 2 * n - 1;//所有结点的个数
	int s1;//最小的结点
	int s2;//第二小的结点
	if (n < 2)return;//n<2时无法构成哈夫曼树
	HT = new HTNode[m + 1];
	//给数组分配空间,一共是2n-1个结点 但是0号下标是不用的
	for (i = 0; i <= m; i++) {
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}

    //创建树
	//从1 开始创建
	for (i = 1; i <= n; i++) {
		printf("请输入第%d个叶子的权:", i);
		scanf_s("%d", &HT[i].weight);
	}
	printf("\nHT的初态\n");
	println(HT, m);
	//从非叶子结点开始创建
	//同时要保证小于数组大小
	//m = 2*n-1
	//m为结点个数
	for (int i = n + 1; i <= m; i++) {
		Select(HT, i - 1, 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;



	}
	printf("哈夫曼树构建成功\n");
	println(HT, m);

}

上面涉及了剩余的两个函数(select println)这里将给出

1. 遍历哈夫曼树组

void println(HuffmanTree& HT, int m)
{
	printf("下图为哈夫曼树的结点遍历\n");
	printf("下标   权   父母结点    左孩子    右孩子\n");
	for (int i = 1; i <= m; i++)
	{

		printf("%d,   ", i);
		printf("%d   ", HT[i].weight);
		printf("%d   ", HT[i].parent);
		printf("%d  ", HT[i].lchild);
		printf("%d   ", HT[i].rchild);
		printf("\n");
	}
}

2. 选择权重最小的两个下标

void Select(HuffmanTree& HT, int n,int &s1,int &s2) {
	//n表示为哈夫曼数组目前的下标
	//s1表示为哈夫曼数组中权重最小的
	//s2表示为哈夫曼数组中权重第二小的
	int min;
	//这个是临时变量,用来存储被s1 和 s2 比较的下标,设置一个基准值
	for (int i = 1; i <= n; i++) {
		if (HT[i].parent == 0) {
			min = i;
			break;
		}
	}
	//上面这个循环用来找到基准值
	for (int i = 1; i <= n; i++) {
		if (HT[i].parent == 0 && HT[i].weight < HT[min].weight) {
			min = i;
		}
	}
	s1 = min;
	//上面这个循环用来找到哈夫曼树中最小权重的下标
	for (int i = 1; i <= n; i++) {
		if (HT[i].parent == 0 && i != s1) {
			min = i;
			break;
		}
	}
	//上面这个循环也是用来寻找基准值
	//最后面的i!=s1 是为了保证寻找的最小值不能是s1,
	//因为s1本身就是最小值,就没有比它大的了
	for (int i = 1; i <= n; i++) {
		if (HT[i].parent == 0 && HT[i].weight < HT[min].weight && i != s1) {
			min = i;
		}
	}
	s2 = min;


}

3. 主函数

int main() {
	HuffmanTree Ht;
	int n;
	printf("请输入叶子数量");
	scanf_s("%d", &n);
	CreathuffmanTree(Ht, n);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值