堆与哈夫曼树

一、堆

1、基本定义

堆是一棵完全二叉树,树中每一个结点的值都不小于(不大于)其左右孩子的值。
大顶堆:父亲结点的值大于等于孩子结点的值。
小顶堆:父亲结点的值小于等于孩子结点的值。
堆一般用于优先队列的实现,而优先队列一般使用大顶堆。

2、堆的操作

(1)堆的表示

const int maxn = 100;
int heap[maxn], n = 100;

(2)向下调整堆

在建立堆的过程中,总是将结点从上往下调整。
调整方法:总是将当前结点V与它的左右孩子比较(如果有的话),假如孩子中存在比结点V大的,就将其中权值最大的那个孩子结点与结点V交换;交换完毕后,继续让结点V与孩子比较,知道结点V的孩子权值都比V小或者是V不存在孩子结点。
调整代码==(时间复杂度是O(logn))== :

//对heap数组在[low, high]范围内进行向下调整
//其中low为欲调整结点的数组下标,high一般为堆的最后一个元素的数组下标
void downAdjust(int low, int high){
	int i = low, j = i * 2;
	while(j < high){
		if(j + 1 < high && heap[j+1] > heap[j]){
			j = j + 1;
		}
		if(heap[j] > heap[i]){
			swap(heap[j], heap[i]);
			i = j;
			j = i * 2;
		}else{
			break;
		}
	}
}

(3)建堆

在这里插入图片描述

//建堆
void createHeap(){
	for(int i = n / 2; i > 0; i--){
		downAdjust(i, n);
	}
}

(4)删除堆顶元素

思路:用最后一个元素覆盖堆顶元素,并且让总个数-1,最后再向下调整堆顶元素。

//删除堆顶元素
void deleteTop(){
	heap[1] = heap[n--];
	downAdjust(1, n);
}

(5)插入元素

思路:往数组末尾添加上欲插入的元素,之后向上调整。
向上调整:总是把欲操作结点与父结点进行比较,如果权值比父结点大,那么交换其与父结点,这样子反复比较,直到到达堆顶或者父亲结点的权值较大为止。

//heap数组在[low, high]范围内进行向上调整
//其中low一般设置为1,high为欲调整的数组下标。
void upAdjust(int low, int high){
	int i = high, j = i / 2;
	while( j >= low ){
		if( heap[j] < heap[i]){
			swap(heap[j], heap[i]);
			i = j;
			j = i / 2;
		}else{
			break;
		}
	}
}

//添加元素
void insert(int x){
	heap[++n] = x;
	upAdjust(1, n);
}

3、堆排序

堆排序:利用堆结构对一个序列进行排序,此处讨论递增排序的情况。
堆排序的直接思路:取出堆顶元素,然后将堆的最后一个元素替换至堆顶,在进行一次针对堆顶元素的向下调整——如此重复,直到堆中只剩下一个元素为止。
实现代码:

void heapSort(){
	createHeap();
	for(int i = n; i > 1; i--){
		swap(heap[i], heap[1]);
		downAdjust(1, i-1);
	}
}

二、哈夫曼树

1、基本定义

叶子结点的路径长度:从根结点出发到达该结点所经过的边数
叶子结点的带权路径长度:把叶子结点的权值乘以其路径长度
树的带权路径长度:所有结点的带权路径长度之和

已知n个数,寻找一棵树,使得树的所有叶子结点的权值恰好为这n个数,并且使得这棵树的带权路径长度最小。带权路径长度最小的树称为哈夫曼树~
对于同一组叶子结点来说,哈夫曼树是不唯一的,但是最小带权路径长度一定是唯一的。

2、算法描述:

1、初始状态有n个结点,结点的权值分别是给定的n个数,将他们视为n棵一个结点的树。
2、合并其中根结点权值最小的两棵树,生成两棵树根结点的父亲结点,权值为这两棵树的权值之和,这样子树的数量就少了一个。
3、重复2、直到只剩下一棵树为止。

一般可以使用优先队列来实现哈夫曼树。

利用优先队列来实现哈夫曼树。

#include <cstdio>
#include <queue>
using namespace std;

priority_queue<long long, vector<long long>, greater<long long >> q;

int main(){
	int n;
	long long temp, x, y, ans = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; i++){
		scanf("%lld", &temp);
		q.push(temp);
	}
	while(q.size() > 1){
		x = q.top();
		q.pop();
		y = q.top();
		q.pop();
		q.push(x + y);
		ans += x + y;
	}
	//ans为最小带权路径
	printf("%lld\n", ans);
	return 0;
}

3、哈夫曼编码

自己看哈~~(doge)

  • 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
发出的红包

打赏作者

艾尔伯特想变瘦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值