哈夫曼树
什么是哈夫曼树
哈夫曼树的定义:给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree),哈夫曼树是带权路径长度最短的树。权值较大的结点离根较近。
-
权:将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。
-
结点的带权路径长度:从根结点到该结点之间路径长度与该结点的权的乘积。
-
树的带权路径长度:树中所有叶子结点的带权路径长度之和
-
前缀码:如果在一个编码系统中,任一个编码都不是其他任何编码的前缀(最左子串),则称该编码系统中的编码是前缀码。例如,一组编码01,001,010,100,110就不是前缀码,因为01是010的前缀,若去掉01或010就是前缀码。例如,名字中的郑霞、郑霞锦就不是前缀码。
-
哈夫曼编码:对一棵具有n个叶子的哈夫曼树,若对树中的每个左分支赋予0,右分支赋予1,则从根到每个叶子的通路上,各分支的赋值分别构成一个二进制串,该二进制串就称为哈夫曼编码。
每次用最小的两个元素构建子树,父节点为两元素之和,按这个规则构成一整颗哈夫曼树。
例如:
计算带权路径:1*7+2*5+3*4+3*2=35
对数据进行一下编码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#define MAX 100
typedef struct HuffManTreeNode
{
int key;
struct HuffManTreeNode* parentNode;
struct HuffManTreeNode* LChild;
struct HuffManTreeNode* RChild;
}Node;
Node* create_node(int key)
{
Node* newNode = (Node*)malloc(sizeof(Node));
assert(newNode);
newNode->key = key;
newNode->LChild = NULL;
newNode->RChild = NULL;
newNode->parentNode = NULL;
return newNode;
}
Node* create_huffmantreeNode(Node* first, Node* second)
{
Node* parentNode = create_node(first->key + second->key);
Node* min = first->key > second->key ? second : first;
Node* max = first->key > second->key ? first : second;
parentNode->LChild = min;
parentNode->RChild = max;
first->parentNode = parentNode;
second->parentNode = parentNode;
return parentNode;
}
//小顶堆
typedef struct Heap
{
int count;
Node** heapData;//用一下二级指针存储多个数据
}Heap;
Heap* create_heap()
{
Heap* heap = (Heap*)malloc(sizeof(Heap));
assert(heap);
heap->count=0;
heap->heapData = (Node**)malloc(sizeof(Node*) * MAX);//max=100 产生100个节点
assert(heap->heapData);
return heap;
}
int size_heap(Heap* heap)
{
return heap->count;
}
bool empty_heap(Heap* heap)
{
return heap->count == 0;
}
void move_heap(Heap* heap, int curPos) //小顶堆
{
while (curPos > 1)
{
Node* min = heap->heapData[curPos];
int parentIndex = curPos / 2;
if (min->key < heap->heapData[parentIndex]->key)
{
heap->heapData[curPos] = heap->heapData[parentIndex];
heap->heapData[parentIndex] = min;
curPos = parentIndex;
}
else
{
break;
}
}
}
void push_heap(Heap* heap, Node* data)
{
heap->heapData[++heap->count] = data;//第一个位置不存储数据
move_heap(heap, heap->count);
}
Node* pop_heap(Heap* heap)
{
Node* min = heap->heapData[1];
int curPos = 1;
int childIndex = curPos * 2;
while (childIndex <= heap->count)
{
Node* temp = heap->heapData[childIndex];
if (childIndex + 1 <= heap->count && temp->key > heap->heapData[childIndex + 1]->key)
{
temp = heap->heapData[++childIndex];
}
heap->heapData[curPos] = temp;
curPos = childIndex;
childIndex *= 2;
}
heap->heapData[curPos] = heap->heapData[heap->count];
move_heap(heap, curPos);
--heap->count;
return min;
}
void print_node(Node* curNode)
{
printf("%d\t", curNode->key);
}
void print_tree(Node* root)
{
if (root != NULL)
{
print_node(root);
print_tree(root->LChild);
print_tree(root->RChild);
}
}
void init_heap(Heap* heap,int array[],int arrayNum)
{
for (int i = 0; i < arrayNum; i++)
{
push_heap(heap, create_node(array[i]));
}
}
Node* create_huffmantree(int array[], int arrayNum)
{
if (arrayNum <= 0)
return NULL;
else if (arrayNum == 1)
return create_node(array[0]);
else
{
Heap* heap = create_heap();
init_heap(heap, array, arrayNum);
Node* root = NULL;
while (!empty_heap(heap))
{
Node* first = pop_heap(heap);
if (empty_heap(heap))
break;
Node* second = pop_heap(heap);
root = create_huffmantreeNode(first, second);
push_heap(heap, root);
}
return root;
}
}
Node* search_huffmantree(Node* tree, int key)
{
Node* pmove = tree;
Node* stack[MAX];//栈结构
int top = -1;
while (pmove != NULL || top != -1)
{
while (pmove != NULL && pmove->key != key)
{
stack[++top] = pmove;
pmove = pmove->LChild;//先找左边
}
if (pmove == NULL)
{
pmove = stack[top--];//回退找右边
pmove = pmove->RChild;
}
else if (pmove->key == key)
{
break;
}
}
return pmove;
}
//打印编码
void print_huffmancode(Node* leaf)
{
Node* pmove = leaf;
int stack[MAX];
int top = -1;
while (pmove != NULL)
{
if (pmove->parentNode != NULL && pmove->parentNode->LChild == pmove)
{
stack[++top] = 0;
}
else if (pmove->parentNode != NULL && pmove->parentNode->RChild == pmove)
{
stack[++top] = 1;
}
else
{
break;
}
pmove = pmove->parentNode;
}
while (top != -1)
{//正常是从向往下的所以出栈就可以了
printf("%d", stack[top--]);
}
printf("\n");
}
void test_huffmantree()
{
int array[] = { 7,5,4,2 };
Node* tree = create_huffmantree(array, 4);
printf("哈夫曼树:");
print_tree(tree);
#if 0
printf("\n查找4:");
Node* pos = search_huffmantree(tree, 4);
printf("%d\n", pos->key);
#endif;
printf("\n哈夫曼编码:\n");
for (int i = 0; i < 4; i++)
{
printf("%d:", array[i]);
print_huffmancode(search_huffmantree(tree, array[i]));
}
}
int main()
{
test_huffmantree();
return 0;
}