# 定义
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);
}