哈夫曼树的非递归创建:
先建立哈夫曼森林(每个带权值的节点都为森林中的一个树),然后将森林中所有的树合并成一个符合哈夫曼编码规则的树,最终哈夫曼树创建完毕。
接着就是通过顺序表输出每个权值的哈夫曼编码。
(具体实现看代码)
#include<stdio.h>
#include<stdlib.h>
//哈夫曼树的节点结构
struct node {
int data;
struct node* parentnode;
struct node* lchild, * rchild;
};
// 顺序表的节点
struct seqList
{
int MAXNUM;
int curNum;
int* element;
};
typedef struct seqList* PseqList;
typedef struct node* Btree;
// 哈夫曼森林
struct forest{
Btree Trees[10];
int CurNum;
};
typedef struct forest* Forest;
/*
创建空的线性表
*/
PseqList createNullList_seq(int m)
{
if (m == 0) return NULL;
PseqList L = (PseqList)malloc(sizeof(struct seqList));
if (L == NULL) return NULL;
L->element = (int*)malloc(sizeof(int) * m);
L->curNum = 0;
L->MAXNUM = m;
if (L->element == NULL)
{
free(L);
return NULL;
}
return L;
}
void printList_seq(PseqList L)
{//逐个输出线性表的元素,相邻的两个数据元素之间以一个空格为分隔符隔开
int i;
for (int i = L->curNum - 1; i >= 0; i--)
{
printf("%d", L->element[i]);
}
}
/*
哈夫曼树的创建
*/
Btree createTree(Btree tree,int x)
{
tree->data = x;
tree->lchild = tree->rchild = NULL;
return tree;
}
/*
找到权值最小的叶子节点返回,并在哈夫曼森林中删除此节点
*/
Btree searchMindata(Forest forest_tree)
{
int temp = 0;
for (int i = 1; i < forest_tree->CurNum; i++)
{
if (forest_tree->Trees[i]->data < forest_tree->Trees[temp]->data)
{
temp = i;
}
}
Btree tree = forest_tree->Trees[temp];
for (int i = temp; i < forest_tree->CurNum - 1; i++)
{
forest_tree->Trees[i] = forest_tree->Trees[i + 1];
}
forest_tree->CurNum--;
return tree;
}
/*
将找到的最小的2个叶子节点相加并存入哈夫曼森林
*/
void addTree(Forest forest_tree)
{
Btree leftTree = searchMindata(forest_tree);
Btree rightTree = searchMindata(forest_tree);
Btree rootTree = (Btree)malloc(sizeof(struct node));
rootTree->data = leftTree->data + rightTree->data;
rootTree->parentnode = NULL;
rootTree->lchild = leftTree;
rootTree->rchild = rightTree;
rightTree->parentnode = leftTree->parentnode = rootTree;
forest_tree->Trees[forest_tree->CurNum] = rootTree;
forest_tree->CurNum++;
}
/*
通过递归先找到等于权值x的叶子节点
然后将哈夫曼编码存入顺序表中并打印出来
*/
void visit(Btree Huffman,int x)
{
if (Huffman == NULL) return;
visit(Huffman->lchild, x);
visit(Huffman->rchild, x);
if (Huffman->data == x)
{
PseqList list = createNullList_seq(10);
while (Huffman->parentnode != NULL)
{
Btree tree = Huffman->parentnode;
if (tree->lchild == Huffman) {
list->element[list->curNum] = 0;
list->curNum++;
}
if (tree->rchild == Huffman) {
list->element[list->curNum] = 1;
list->curNum++;
}
Huffman = Huffman->parentnode;
}
printList_seq(list);
printf("\n");
return;
}
}
/*
setList函数为了从左到右找到创建好的哈夫曼树的每个叶子节点然后存入顺序表中
(目的:为了按老师的顺序输出结果)
*/
void setList(PseqList L,Btree Huffman)
{
if (Huffman->lchild == NULL && Huffman->rchild == NULL)
{
L->element[L->curNum] = Huffman->data;
L->curNum++;
return;
}
setList(L, Huffman->lchild);
setList(L, Huffman->rchild);
}
int main() {
int n;
scanf("%d", &n);
Forest forest_tree = (Forest)malloc(sizeof(struct forest));
forest_tree->CurNum = n;
PseqList L = createNullList_seq(10);
int a[10];
for (int i = 0; i < n; i++)
{
forest_tree->Trees[i] = (Btree)malloc(sizeof(struct node));
int x;
scanf("%d", &x);
a[i] = x;
createTree(forest_tree->Trees[i], x);
}
while (forest_tree->CurNum > 1)
{
addTree(forest_tree);
}
Btree Huffman = forest_tree->Trees[0];
setList(L, Huffman);
for (int i = 0; i < n; i++)
{
printf("%d ", L->element[i]);
visit(Huffman, L->element[i]);
}
}