3.树之堆、哈夫曼树以及集合

(一)堆的定义

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

若采用数组或者链表实现优先队列:

  1. 数组
    插入:元素总是插入尾部 ~O(1)
    删除:查找最大(最小)关键字 ~O(n)
    ———从数组中删除元素并移动~O(n)

  2. 链表
    插入:元素总是插入链表的头部~O(1)
    删除:查找最大(最小)关键字 ~O(n)
    ————删去结点 ~O(1)

  3. 有序数组
    插入:找到合适的位置~O(n)或O(log2n)
    ————移动元素并且插入~O(n)
    删除:删去最后一个元素~O(1)

  4. 有序链表
    插入:找到合适的位置~O(n)
    ———插入元素~O(1)
    删除:删除首元素或者最后元素~O(1)

是否可以采用二叉树存储结构?

  • 二叉搜索树:每次删除最大的,意味着每次都删除右子树,那么树就不平衡了。
  • 如果采用二叉树结构,应该更关注插入还是删除?
    树的结点顺序怎么安排? 最大的/最小的保存在树根
    树结构怎么样?完全二叉树

堆的两个特性

  • 结构性:用数组表示的完全二叉树
  • 有序性:任意结点的关键字是其子树所有结点的最大值(或最小值)
    最大堆:大堆顶
    最小堆:小顶堆
    在这里插入图片描述
    最大堆和最小堆每一条路径都满足:从大到小或从小到大,且都是完全二叉树
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

(二)最大堆的建立

  • 方法1:通过插入操作,将N个元素一个个相机插入到一个促使为空的堆中去,其时间代价最大为O(NlogN)
  • 方法2:在线性时间复杂度下建立最大堆
    (1)将N个元素按输入顺序存入,先满足完全二叉树的结构特性
    (2)调整各结点的位置,以满足最大堆的有序特性
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    **建堆时,最坏情况下需要挪动元素次数是等于树中各结点的高度和。**问:对于元素个数为12的堆,其各结点的高度之和是多少?
    1
    2 3
    4 5 6 7
    8 9 10 11 12
    建堆的话,主要考虑下沉的次数,以此定义高度。8,9,10,11,12都是已经沉底的,要注意的是7也是在最底了。这些节点高度都是0。
    4,5,6都是最多可以沉1次的,高度为1.
    2,3最多能沉2次,高度为2.
    1可以沉3次,高度为3.
    1*3+2*2+3*1=3+4+3=10

05-树7 堆中的路径 (25 分)
将一系列给定数字插入一个初始为空的小顶堆H[]。随后对任意给定的下标i,打印从H[i]到根结点的路径。
输入格式:
每组测试第1行包含2个正整数N和M(≤1000),分别是插入元素的个数、以及需要打印的路径条数。下一行给出区间[-10000, 10000]内的N个要被插入一个初始为空的小顶堆的整数。最后一行给出M个下标。
输出格式:
对输入中给出的每个下标i,在一行中输出从H[i]到根结点的路径上的数据。数字间以1个空格分隔,行末不得有多余空格。

输入样例:
5 3
46 23 26 24 10
5 4 3
输出样例:
24 23 10
46 23 10
26 10

题意理解:在这里插入图片描述

#include <vector>
#include <stdio.h>
#include <iostream>
using namespace std;

//05-树7 堆中的路径 (25 分)
#define MAXN 1001
#define MINH -10001
int heap[MAXN];
int h_size;

//建立一个空堆
void Create()
{
   
	h_size = 0;
	heap[0] = MINH;		 /*设置“岗哨”*/
}

//最小堆的插入,方法是从最后一个结点开始比较
void Insert(int X)
{
   
	//省略判断堆是否已满
	int i;
	for (i = ++h_size; heap[i / 2] > X; i /= 2){
   
		heap[i] = heap
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值