数据结构之哈夫曼树

哈夫曼树

什么是哈夫曼树

哈夫曼树的定义:给定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;
}

 

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值