堆和哈夫曼树

什么是堆

优先队列(Priority Queue)

特殊的“队列”,取出元素的顺序依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序

  1. 采用数组实现优先队列
  • 插入——元素总是插入尾部
  • 删除——查找最大(或最小)关键字,从数组中删去需要移动的元素
  1. 采用链表实现优先队列
  • 插入——元素总是插入链表头部
  • 删除——查找最大(或最小)关键字删除结点
  1. 采用有序数组实现优先队列
  • 插入——找到合适位置移动元素并插入
  • 删除——删去最后一个元素
  1. 采用有序链表实现优先队列
  • 插入——找到合适的位置插入元素
  • 删除——删除首元素或最后元素
  1. 采用完全二叉树存储结构(最优)

堆的两个特性

  1. 结构性:数组表示的完全二叉树
  2. 有序性:任一结点的关键字是其子树所有结点的最大值(或最小值)
  • 最大堆(MaxHeap)”,也称“大顶堆”:最大值
  • 最小堆(MinHeap)”,也称“小顶堆”:最小值

堆的抽象数据类型描述

类型名:最大堆(MaxHeap)
数据对象集:完全二叉树,每个结点的元素值不小于其子节点的值

1.最大堆的创建

typedef struct HeapStruct *MaxHeap;
struct HeapStruct
{
	ElementType *Elements;/*存储堆元素的数组*/
	int Size;/*堆的当前元素个数*/
	int Capacity;/*堆的最大容量*/	
}
MaxHeap Create(int MaxSize)
{
	MaxHeap H = malloc(sizeof(struct HeapStruct));
	H->Elements = malloc((MaxSize+1) * sizeof(ElementType));
	H->Size = 0;
	H->Capacoty = MaxSize;
	H->Elements[0] = MaxData;/*定义为“哨兵”,为大于堆中所有元素的值,方便以后操作*/
	return H;
}

2. 最大堆的插入

void Insert(MaxHeap H,ElementType item)
{
	int i;
	if(isFull(H))
	{/*最大堆已满*/
		return;
	}
	i = ++H->Size;/*i指向插入后堆中的最后一个元素的位置*/
	for( ;H->Elements[i / 2] < item; i /= 2)
	{
		H->Elements[i] = H->Elements[i / 2];
	}
	H->Elements[i] = item;
}

3. 最大堆的删除

ElementType DeleteMax(MaxHeap H)
{
	int parent,child;
	ElementType MaxItem,temp;
	if(IsEmpty(H))
	{/*如果堆为空就没有必要删除*/
		return;
	}
	MaxItem = H->Elements[1];/*取出根结点最大值*/
	temp = H->ElementType[H->Size--];/*删除一个元素后大小要减1*/
	for(parent = 1; parent * 2 <= H->Size/*判别有没有左儿子*/; parent = child)
	{
		child = parent * 2;
		if( (child != H->Size) /*判别有没有右儿子*/&& 
			(H->Elements[child] < H->Elements[child + 1]) )
		{/*把child指向左右儿子中大的*/
			child++;
		}
		if(temp >= H->Elements[child]) break;/*如果temp大于左右儿子就直接插入*/
		else
		{
			H->ELements[parent] = H->Elements[child];		
		}
	}
	H->Elements[parent] = temp;
	return MaxIteml
}

最大堆的建立

堆的应用:堆排序

  1. 通过插入操作,将N个元素一个个相继插入到一个初始为空的堆中去
  2. 线性时间复杂度下建立最大堆
  • 将N个元素按输入顺序存入,先满足完全二叉树的结构特性
  • 调整各结点的位置以满足最大堆的特性

哈夫曼树与哈夫曼编码

哈夫曼树的定义

带权路径长度(WPL),设二叉树有n个叶子结点每个叶子结点带有权值Wk从根节点到每个叶子结点的长度为Ik,则每个叶子结点的带权路径长度之和就是:在这里插入图片描述
最优二叉树和或哈夫曼树:WPL最小的二叉树

哈夫曼树的构造

每次把权值最小的两棵二叉树合并

typedef struct TreeNode *HufffmanTree;
struct TreeNode
{
	int weight;
	HuffmanTree Left,Right;
}
HuffmanTree Huffman( MinHeap H )
{
	int i;
	HuffmanTree T;
	BuildMinHeap(H);/*将H->Elements[]按权值调整为最小堆*/
	for(int i = 1; i < H->Size; i++)
	{	
		T = malloc(sizeof(struct TreeNode));
		T->Left = DeleteMin(H);/*从最小堆中删除一个结点*/
		T->Right = DeleteMin(H);/*从最小堆中删除一个结点*/
		T->Weight = T->Left->Weight + T->Right->Weight;
		Insert(H,T);
	}
	T = DeleteMin(H);
	return T;
}

哈夫曼树的特点

  • 没有度为1的结点
  • n个叶子结点的哈夫曼树共有2n - 1个结点
  • 哈夫曼树任意非叶结点的左右子树交换后仍是哈夫曼树
  • 对于同一组权值,存在不同构的两棵哈夫曼树,但WPL相同

哈夫曼编码

前缀码(prefix code):任何字符的编码都不是另一个字符编码的前缀,可以避免二义性
采用二叉树进行编码

  • 左右分支:0,1
  • 字符只在叶结点

参考题目05-树9:Huffman Codes (30分)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最小堆是一种特殊的二叉堆,它满足以下性质: 1. 每个节点的值都小于或等于其子节点的值。 2. 堆中的最小元素位于根节点。 哈是一种用于数据压缩的形结构,它通过将出现频率较高的字符编码为较短的二进制码,从而实现数据的高效压缩。构建哈的过程中,需要使用最小堆来选择频率最低的两个节点进行合并。 下面是使用C语言实现最小堆构建哈的基本步骤: 1. 定义一个结构体来表示节点,包括字符、频率和左右子节点等信息。 ```c struct Node { char data; int freq; struct Node* left; struct Node* right; }; ``` 2. 创建一个最小堆,并初始化为空。 ```c struct MinHeap { int size; int capacity; struct Node** array; }; ``` 3. 实现最小堆的一些基本操作,如交换节点、调整节点位置等。 ```c void swapNode(struct Node** a, struct Node** b); void minHeapify(struct MinHeap* minHeap, int index); struct Node* extractMin(struct MinHeap* minHeap); void insertMinHeap(struct MinHeap* minHeap, struct Node* node); ``` 4. 构建最小堆,将每个字符的频率作为节点的值,并插入到最小堆中。 ```c struct MinHeap* createAndBuildMinHeap(char data[], int freq[], int size); ``` 5. 构建哈,不断从最小堆中取出频率最低的两个节点,合并为一个新节点,并将新节点插入到最小堆中,直到最小堆中只剩下一个节点为止。 ```c struct Node* buildHuffmanTree(char data[], int freq[], int size); ``` 6. 打印哈的编码,通过遍历哈的路径来获取每个字符的编码。 ```c void printCodes(struct Node* root, int arr[], int top); ``` 这是一个简单的介绍,如果你需要更详细的代码实现或者有其他问题,请告诉我。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值