数据结构-哈夫曼树

一.什么是哈夫曼树

不同搜索树的效率是不一样的,根据不同的频率构造效率比较好或者最好的搜索树就是哈夫曼树

二.哈夫曼树的定义

将带权路径的长度降低最低

每个叶子节点到根节点的距离乘权值,再全都加起来就得到了WPL值

第一颗二叉树:从上到下计算 5x1+4x2+3x3+2x4+1x4=34

第二颗二叉树:从上到下计算 1x1+2x2+3x3+4x4+5x4=50

第二颗二叉树:从上到下计算 1x3+2x3+3x2+4x2+5x2=33

哈夫曼树为了构造一个树WPL最小

三.哈夫曼树的构造

构造哈夫曼树的方法从小到大排序,将最小的两个权值并在一起形成新的二叉树,这个二叉树的权值就是并在一起两个权值的和,再把这个根形成的根节点放到序列中重新按照从小到大排序,然后重复上面的操作,直到所有节点都用完

下面的列子权值  (1,2,3,4,5,6)

实现哈夫曼树的代码

把节点权值构造成最小堆,从里面找出两个最小和在一起形成一个新的节点在插入到堆中,也可以用排序的方法但不如堆的效率高.

#include<iostream>
using namespace std;
typedef struct HNode* Heap;
typedef struct TreeNode* HuffmanTree;
typedef HuffmanTree ElementType;
int A[] = { 13,1,45,7,20,4,19,13,40,33,38 };  // 预先定义好一组权值 
int A_length = 11;  // 定义其长度 
struct TreeNode
{
	int Weight;//权值
	HuffmanTree Left, Right;//左右孩子
};
struct HNode {
	ElementType* Data;//存储哈夫曼的数组
	int Size;//当前堆元素的个数
	int Capacity;//堆的最大容量
};
HuffmanTree CreateHuffman() {
	HuffmanTree Huffman = new TreeNode();
	Huffman->Weight = 0;
	Huffman->Right = Huffman->Left = NULL;
	return Huffman;
}
typedef Heap MinHeap;//最小堆
#define MINDATA -1000;
MinHeap CreateHeap(int MaxSize) {
	//创建容量为MinSize的空的最小堆
	MinHeap H = new HNode();
	H->Data = new ElementType[MaxSize + 1];
	H->Size = 0;
	H->Capacity = MaxSize;
	HuffmanTree man = CreateHuffman();
	man->Weight = MINDATA;
	H->Data[0] = man;
	return H;
}

bool Insert(MinHeap H, ElementType X) {
	int i;
	i = ++H->Size;/*增加树的元素*/
	/*根节点元素大于插入的元素根节点元素从根节点到子节点*/
	for (; H->Data[i / 2]->Weight > X->Weight; i /= 2)
		H->Data[i] = H->Data[i / 2];/*根节点下来*/
	H->Data[i] = X;
	return true;
}

ElementType DeleteMin(MinHeap H) {
	int Parent, Child;
	ElementType MinHuffman, X;
	MinHuffman= H->Data[1];//取出根节点存放的最小值
	X = H->Data[H->Size--];//取出堆最后一个值并删除
	/*Parent*2<=H->Size判断左子树是否存在
	Parent*2>H->Size 表示左字数不存在*/
	for (Parent = 1; Parent * 2 <= H->Size; Parent = Child) {/*向下到左右树最小的地方*/
		Child = Parent * 2;
		/*Child!=H->Size判断右子树是否存在,
		左子树等于Size表明左子树是最后一个元素
		所以右子树不存在*/
		if ((Child != H->Size) && (H->Data[Child + 1]->Weight < H->Data[Child]->Weight))
			Child++;
		if (H->Data[Child]->Weight >= X->Weight)break;
		else
			/*左右儿子中最小的值上来*/
			H->Data[Parent] = H->Data[Child];
	}
	H->Data[Parent] = X;
	return MinHuffman;
}
void PercDown(MinHeap H, int p) {
	int Parent, Child;
	ElementType X;
	X = H->Data[p];//取出根节点
	for (Parent = p; Parent * 2 <= H->Size; Parent = Child) {
		Child = Parent * 2;
		if ((Child != H->Size) && (H->Data[Child + 1]->Weight < H->Data[Child]->Weight))
			Child++;
		if (H->Data[Child]->Weight >= X->Weight)
			break;
		else
			H->Data[Parent] = H->Data[Child];
	}
	H->Data[Parent]->Weight = X->Weight;
}
void BuildHeap(MinHeap H) {
	/*调整H->Data[]中的元素,使满足小堆的有序性*/
	/*这里假设所有H->Size个元素已经存在H->Data[]中*/
	/*从最后一个节点的父节点开始,到根节点1*/
	int i;
	for (i = H->Size / 2; i > 0; i--)
		PercDown(H, i);
}
void BuildMinHeap(MinHeap H) {
	HuffmanTree Huff;
	for (int i = 0; i < A_length; i++) {
		Huff = CreateHuffman();
		Huff->Weight = A[i];
		H->Data[++H->Size] = Huff;
	}
	BuildHeap(H);
}
//遍历 
void PreOrderTraversal(HuffmanTree Huff) {
	if (Huff) {
		cout << Huff->Weight << " ";
		PreOrderTraversal(Huff->Left);
		PreOrderTraversal(Huff->Right);
	}
}
HuffmanTree Huffman(MinHeap H) {
	HuffmanTree T;
	BuildMinHeap(H);
	int times = H->Size;
	for (int i = 1; i < times; i++) {
		T = new TreeNode();
		T->Left = DeleteMin(H);
		T->Right = DeleteMin(H);
		T->Weight = T->Right->Weight + T->Left->Weight;
		Insert(H, T);
	}
	T = DeleteMin(H);
	return T;
}
int main()
{
	MinHeap H;
	HuffmanTree Huff;
	H = CreateHeap(1000);
	Huff = Huffman(H);
	PreOrderTraversal(Huff);
	return 0;
	
}

四.哈夫曼树的特点

1.特点没有度唯1的节点因为每个节点都是两个权值合并在一起形成的

五.哈夫曼编码

当所有的节点都在叶节点就不可能出现一个字符编码是另一个字符的前缀,当你编码节点出现在另外一个编码节点当中的时候在树的非叶节点上的时候会场出现前缀

上一篇:【深度学习目标检测|YOLO算法2】YOLO家族进化史:从YOLOv1到YOLOv11的架构创新、性能优化与行业应用全解析...


下一篇:redis用法(二)