什么是堆

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

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

数组 :

插入 — 元素总是插入尾部 ~ Θ\ThetaΘ ( 1 )
删除 — 查找最大(或最小)关键字 ~ Θ\ThetaΘ ( n )
从数组中删去需要移动元素 ~ O( n )

链表:

插入 — 元素总是插入链表的头部 ~ Θ\ThetaΘ ( 1 )
删除 — 查找最大(或最小)关键字 ~ Θ\ThetaΘ ( n )
删去结点 ~ Θ\ThetaΘ ( 1 )

有序数组:

插入 — 找到合适的位置 ~ O( n ) 或 O(log2log_2log2​ n )
移动元素并插入 ~ O( n )
删除 — 删去最后一个元素 ~ Θ\ThetaΘ ( 1 )

有序链表:

插入 — 找到合适的位置 ~ O( n )
插入元素 ~ Θ\ThetaΘ ( 1 )
删除 — 删除首元素或最后元素 ~ Θ\ThetaΘ ( 1 )

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

二叉搜索树? 一直删除最大的结点导致树变斜,不能采用

如果采用二叉树结构,需要做两个操作:插入任何结点、删除最大值,其中更应关注删除最大值(因为更难做)。可以考虑将树构造成 将最大值放在树根,删除最大值就将根结点拿掉,这就是最大堆。使用完全二叉树存储。

优先队列的完全二叉树表示

堆的两个特性

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

【例子】:
最大堆:

最小堆:

不是堆:

不是完全二叉树
不满足根结点是最大的/最小的

注意:从根结点到任意结点路径上结点序列的有序性!

堆的抽象数据类型描述

类型名称:最大堆(MaxHeap)
数据对象集:完全二叉树,每个结点的元素值不小于其子结点的元素值
操作集:最大堆H ∈\in∈MaxHeap,元素item ∈\in∈ ElementType,主要操作有:
MaxHeap Create( int MaxSize ):创建一个空的最大堆。
Boolean IsFull( MaxHeap H ):判断最大堆H是否已满。
Insert( MaxHeap H, ElementType item ):将元素item插入最大堆H。
Boolean IsEmpty( MaxHeap H ):判断最大堆H是否为空。
ElementType DeleteMax( MaxHeap H ):返回H中最大元素(高优先级)。

最大堆的操作

创建

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

插入

算法:将新增结点插入到从其父结点到根结点的有序序列中

void Insert( MaxHeap H, ElementType item )
{
/* 将元素item 插入最大堆H, 其中H->Elements[0]已经定义为哨兵 */int i;if ( IsFull(H) ) {printf("最大堆已满");return;
}
i= ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */
for ( ; H->Elements[i/2] < item; i/=2 )H->Elements[i] = H->Elements[i/2]; /* 向下过滤结点 */
H->Elements[i] = item; /* 将item 插入 */
}

我们设置H->Element[ 0 ] 是哨兵元素,它不小于堆中的最大元素,控制循环结束。
时间复杂度T(N) = log2log_2log2​ N (树的高度)

删除

ElementType DeleteMax( MaxHeap H )
{   /* 从最大堆H中取出键值为最大的元素, 并删除一个结点 */int Parent, Child;ElementType MaxItem, temp;if ( IsEmpty(H) ) {printf("最大堆已为空");return;}MaxItem = H->Elements[1]; /* 取出根结点最大值 *//* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */temp = H->Elements[H->Size--];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;else /* 移动temp元素到下一层 */H->Elements[Parent] = H->Elements[Child];} H->Elements[Parent] = temp;return MaxItem;

最大堆的建立

建立最大堆: 将已经存在的N个元素按最大堆的要求存放在一个一维数组中

方法1: 通过插入操作,将N个元素一个个相继插入到一个初
始为空的堆中去,其时间代价最大为O(N logN)。

方法2: 在线性时间复杂度下建立最大堆。
(1)将N个元素按输入顺序存入,先满足完全二叉树的结构特性
(2)调整各结点位置,以满足最大堆的有序特性

完整代码

typedef struct HNode *Heap; /* 堆的类型定义 */
struct HNode {ElementType *Data; /* 存储元素的数组 */int Size;          /* 堆中当前元素个数 */int Capacity;      /* 堆的最大容量 */
};
typedef Heap MaxHeap; /* 最大堆 */
typedef Heap MinHeap; /* 最小堆 */#define MAXDATA 1000  /* 该值应根据具体情况定义为大于堆中所有可能元素的值 */MaxHeap CreateHeap( int MaxSize )
{ /* 创建容量为MaxSize的空的最大堆 */MaxHeap H = (MaxHeap)malloc(sizeof(struct HNode));H->Data = (ElementType *)malloc((MaxSize+1)*sizeof(ElementType));H->Size = 0;H->Capacity = MaxSize;H->Data[0] = MAXDATA; /* 定义"哨兵"为大于堆中所有可能元素的值*/return H;
}bool IsFull( MaxHeap H )
{return (H->Size == H->Capacity);
}bool Insert( MaxHeap H, ElementType X )
{ /* 将元素X插入最大堆H,其中H->Data[0]已经定义为哨兵 */int i;if ( IsFull(H) ) { printf("最大堆已满");return false;}i = ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */for ( ; H->Data[i/2] < X; i/=2 )H->Data[i] = H->Data[i/2]; /* 上滤X */H->Data[i] = X; /* 将X插入 */return true;
}#define ERROR -1 /* 错误标识应根据具体情况定义为堆中不可能出现的元素值 */bool IsEmpty( MaxHeap H )
{return (H->Size == 0);
}ElementType DeleteMax( MaxHeap H )
{ /* 从最大堆H中取出键值为最大的元素,并删除一个结点 */int Parent, Child;ElementType MaxItem, X;if ( IsEmpty(H) ) {printf("最大堆已为空");return ERROR;}MaxItem = H->Data[1]; /* 取出根结点存放的最大值 *//* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */X = H->Data[H->Size--]; /* 注意当前堆的规模要减小 */for( Parent=1; Parent*2<=H->Size; Parent=Child ) {Child = Parent * 2;if( (Child!=H->Size) && (H->Data[Child]<H->Data[Child+1]) )Child++;  /* Child指向左右子结点的较大者 */if( X >= H->Data[Child] ) break; /* 找到了合适位置 */else  /* 下滤X */H->Data[Parent] = H->Data[Child];}H->Data[Parent] = X;return MaxItem;
} /*----------- 建造最大堆 -----------*/
void PercDown( MaxHeap H, int p )
{ /* 下滤:将H中以H->Data[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]<H->Data[Child+1]) )Child++;  /* Child指向左右子结点的较大者 */if( X >= H->Data[Child] ) break; /* 找到了合适位置 */else  /* 下滤X */H->Data[Parent] = H->Data[Child];}H->Data[Parent] = X;
}void BuildHeap( MaxHeap H )
{ /* 调整H->Data[]中的元素,使满足最大堆的有序性  *//* 这里假设所有H->Size个元素已经存在H->Data[]中 */int i;/* 从最后一个结点的父节点开始,到根结点1 */for( i = H->Size/2; i>0; i-- )PercDown( H, i );
}

【数据结构】堆 笔记相关推荐

  1. 大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 21

    大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 211 第 ...

  2. 数据结构学习笔记(王道)

    数据结构学习笔记(王道) PS:本文章部分内容参考自王道考研数据结构笔记 文章目录 数据结构学习笔记(王道) 一.绪论 1.1. 数据结构 1.2. 算法 1.2.1. 算法的基本概念 1.2.2. ...

  3. 数据结构学习笔记(3-5):树

    附录:所有blog的链接 数据结构学习笔记(1):基本概念 数据结构学习笔记(2):线性结构 数据结构学习笔记(3-5):树 数据结构学习笔记(6-8):图 数据结构学习笔记(9-10):排序 数据结 ...

  4. 数据结构学习笔记(七):哈希表(Hash Table)

    目录 1 哈希表的含义与结构特点 1.1 哈希(Hash)即无序 1.2 从数组看哈希表的结构特点 2 哈希函数(Hash Function)与哈希冲突(Hash Collision) 2.1 哈希函 ...

  5. 数据结构学习笔记(六):二叉树(Binary Tree)

    目录 1 背景知识:树(Tree) 2 何为二叉树(Binray Tree) 2.1 二叉树的概念与结构 2.2 满二叉树与完全二叉树 2.3 二叉树的三种遍历方式 3 二叉树及其遍历的简单实现(Ja ...

  6. 数据结构学习笔记(五):重识字符串(String)

    目录 1 字符串与数组的关系 1.1 字符串与数组的联系 1.2 字符串与数组的区别 2 实现字符串的链式存储(Java) 3 子串查找的简单实现 1 字符串与数组的关系 1.1 字符串与数组的联系 ...

  7. 数据结构学习笔记(四):重识数组(Array)

    目录 1 数组通过索引访问元素的原理 1.1 内存空间的连续性 1.2 数据类型的同一性 2 数组与链表增删查操作特性的对比 2.1 数组与链表的共性与差异 2.2 数组与链表增删查特性差异的原理 3 ...

  8. 数据结构学习笔记——顺序表的基本操作(超详细最终版+++)建议反复看看ヾ(≧▽≦*)o

    目录 前言 一.顺序表的定义 二.顺序表的初始化 三.顺序表的建立 四.顺序表的输出 五.顺序表的逆序输出 六.顺序表的插入操作 七.顺序表的删除操作 八.顺序表的按位和按值查找 基本操作的完整代码 ...

  9. Python数据结构学习笔记——链表:无序链表和有序链表

    目录 一.链表 二.无序链表 实现步骤分析 三.无序链表的Python实现代码 四.有序链表 实现步骤分析 五.有序链表的Python实现代码 结语 一.链表 链表中每一个元素都由为两部分构成:一是该 ...

  10. Python数据结构学习笔记——队列和双端队列

    目录 一.队列的定义 二.队列 实现步骤分析 三.队列的Python实现代码 四.队列的应用 六人传土豆游戏 五.双端队列的定义 六.双端队列 实现步骤分析 七.双端队列的Python实现代码 八.双 ...

最新文章

  1. 如何用Map、Filter和Reduce替换Python For循环?
  2. mysql like 多个条件_MySQL高性能索引策略
  3. C语言实现随机生成0~100的数
  4. MySQL 1093 You can't specify target table for update in FROM c 的解决办法
  5. 方差分析 球形检验_两因素重复测量设计做方差分析时,球形检验没有结果怎么回事?...
  6. ActiveMQ与spring整合
  7. 学好Python爬取京东知乎价值数据
  8. 2.mysql数据库如何安装_MySQL数据库如何安装
  9. 2018下半年软考报名
  10. u盘不显示盘符但能识别怎么回事
  11. Windows任务管理器
  12. 《WF编程》系列之29 - 本地通信事件:HandleExternalEventActivity 活动生成器
  13. 一文带你理解URI 和 URL 有什么区别?
  14. 外星人电脑装linux双系统,在外星人电脑上安装windows10和ubuntu16.04双系统小记
  15. strpos php 中文,php strpos是什么
  16. 179. Largest Number
  17. # Python第一节课
  18. 【从0到1搭建LoRa物联网】11、ASR6505 LoRaWAN通信
  19. 图像超分论文阅读列表 super_resolution_paper_lists
  20. 苹果最新系统ios7_安卓微信7.0.16内测版 诚邀你参加内测!ios7.0.13正式版发布

热门文章

  1. 基于TCP实现双向通信对话功能
  2. notepad++ 远程连接阿里云服务器
  3. spring事务管理-注解配置aop事务(重点)
  4. 递归 递归的案例 递归的案例
  5. goahead php,Goahead移植教程 | 学步园
  6. RabbitMq链接
  7. mysql使用常量列_MySQL 执行计划
  8. 200915阶段一C++模板
  9. 笔记本电脑建wifi
  10. vue 开发一个按钮组件