#include<stdio.h>
#include<stdlib.h>
struct HaTree {
int weight;
HaTree *left;
HaTree *right;
};
struct MinHeap {
//data代表HaTree的数组,也就是数组,只不过动态指定大小的
//size记录当前堆的元素个数
//capacity 记录堆的最大容量,
HaTree *data;
int size;
int capacity;
};
//最小堆的初始化
MinHeap* createMinHeap(int capacity) {
MinHeap * h = (MinHeap *)malloc(sizeof(MinHeap));
h->data = (HaTree *)malloc((capacity + 1) * sizeof(HaTree));
h->size = 0;
h->capacity = capacity;
h->data[0].weight = -100000;
h->data[0].left = NULL;
h->data[0].right = NULL;
return h;
}
//最小堆插入元素,这个是为了提供当构造哈夫曼数产生新的节点时要插入最小堆使用的插入函数
void insertMinHeap(MinHeap *head, HaTree *T) {
//判断该堆是否满了
if (head->size == head->capacity) {
printf("该最小堆已经满了\n");
return;
}
int i = head->size;
//表示添加了一个元素
i++;
head->size++;
for (; head->data[i / 2].weight > T->weight; i = i / 2) {
head->data[i].weight = head->data[i / 2].weight;
head->data[i].left = head->data[i / 2].left;
head->data[i].right = head->data[i / 2].right;
}
//新插入的节点必定有左右子树,所以不为空
head->data[i].weight = T->weight;
head->data[i].left = T->left;
head->data[i].right = T->right;
}
// 最小堆插入元素(个人没有采用另外一种方式,先把数据插入到堆中,然后进行调整)
//个人采用的每次插入一个元素后,此时已经是最小堆啦 ,这种方式比较浪费时间,但是容易理解
void init_insert_heap(MinHeap *head, int w) {
//判断该堆是否满了
if (head->size == head->capacity) {
printf("该最小堆已经满了\n");
return;
}
int i = head->size;
//表示添加了一个元素
i++;
head->size++;
for (; head->data[i / 2].weight > w; i = i / 2) {
head->data[i].weight = head->data[i / 2].weight;
}
//这个地方为啥要把左右子树为空,因为这些点最终都哈夫曼树的叶子节点,左右子树都空
head->data[i].weight = w;
head->data[i].left = NULL;
head->data[i].right = NULL;
}
//删除最小堆中的最小元素
HaTree * delete_min(MinHeap *head) {
if (head->size == 0) {
printf("最小堆已经空了,请检查下你的操作\n");
return NULL;
}
HaTree *node = (HaTree *)malloc(sizeof(HaTree));
node->weight = head->data[1].weight;
node->left = head->data[1].left;
node->right = head->data[1].right;
int parent, child = 0;
//这么写的目的为了好理解
int temp = head->data[head->size].weight;
head->size--;
for (parent = 1; parent * 2 <= head->size; parent = child) {
child = parent * 2;
if (child != head->size && (head->data[child + 1].weight < head->data[child].weight))
child++;
if (head->data[child].weight > temp)
break;
else {
head->data[parent].weight = head->data[child].weight;
head->data[parent].left = head->data[child].left;
head->data[parent].right = head->data[child].right;
}
}
head->data[parent].weight = temp;
//注意理解head->size+1 和head->size++
head->data[parent].left = head->data[head->size + 1].left;
head->data[parent].right = head->data[head->size + 1].right;
//返回取出的最小堆的节点
return node;
}
//建立哈夫曼树
HaTree * buildTree(MinHeap *head) {
HaTree *ha = NULL;
//最后一个直接从最小堆中取出,所以注意判断的条件
while (head->size>1)
{
ha = (HaTree *)malloc(sizeof(HaTree));
ha->left = delete_min(head);
ha->right = delete_min(head);
ha->weight = ha->left->weight + ha->right->weight;
insertMinHeap(head, ha);
}
ha = delete_min(head);
return ha;
}
//遍历下哈夫曼树,先序遍历
void preOrder(HaTree *p) {
if (p) {
printf("%d\n", p->weight);
preOrder(p->left);
preOrder(p->right);
}
}
int main() {
MinHeap * head = createMinHeap(20);
int a[] = { 1,3,4,5 };
int length = sizeof(a) / sizeof(a[0]);
//对哈夫曼树的进行权重的初始化
for (int i = 0; i < length; i++) {
init_insert_heap(head, a[i]);
}
HaTree *p = buildTree(head);
preOrder(p);
printf("hello");
system("pause");
return 0;
}