优先队列(priority queue)
2016-06-29 18:05
537 查看
定义
优先队列是一种支持以下主要操作的抽象数据结构:Insert(p):添加一个带有优先权p的新元素
ExtractMax():取出具有最大优先权的元素
其他操作:
Remove(it):删除it迭代器指向的一个元素
GetMax():返回具有最大优先权的元素(不改变元素集合)
ChangePriority(it,p):把it迭代器指向的元素权限改为p
使用优先队列的算法
Dijsktra’s algorithmPrims’ algorithm
Huffman’s algorithm
Heap Sort
优先队列的实现
二叉堆
定义
二叉堆是每个结点值大于等于它的孩子结点值的二叉树(每个结点只有0、1或2个孩子结点)。也就是树的每一条枝上的结点值不小于它的孩子结点。基本操作
GetMax()直接返回根节点的值
Insert(it, p)
1.在任意一个叶子结点插入新结点(这会引起堆属性的变化)
2.调整。新结点上移,也就是问题结点和与它连接的父母结点交换直到满足堆的属性
ExtractMax()
1.利用任意一个叶子结点替换根节点(这会引起堆的属性发生变化)
2.调整。问题结点下移,也就是问题结点和与它连接的较大孩子结点交换,直到满足堆的属性
ChangPriority()
1.更改指定结点的优先级(这会引起堆属性的变化)
2.根据指定结点的优先级是增大还是减小,上移或下移问题结点,直至满足堆的属性
Remove()
1.把要删除的结点的优先级更改为无穷大(这会引起堆的属性发生变化)
2.调整。问题结点上移,也就是把要删除的结点和与它连接的父母节点交换,直至满足堆的属性
调用ExtractMax()删除根节点
总结
时间复杂度 | |
---|---|
GetMax() | O(1) |
Insert() | O(n) |
ExtractMax() | O(n) |
ChangePriority() | O(n) |
Remove | O(n) |
完全二叉树
定义
1.二叉树2.最后一层的结点居于最左端
3.其它层结点数达到最大
优势
1.树的高度低一颗包含n个结点的完全二叉树最大高度为O(log n)
2.可以存成数组
parent(i) = i/2(向下取整)
LeftChild(i) = 2 * i
RightChild(i) = 2 * i + 1
缺点
保持完全二叉树的属性插入一个元素:把要插入的结点当做叶子结点插入到最后一层的最左端空白位置,然后上移元素
删除最大值:用最后的叶子结点替代根节点,然后下移替代根节点之后的叶子结点
伪代码实现
基本设置
1.maxSize:堆中元素个数的最大值2.size:堆的大小
3.H[1…maxSize]:长度为maxSize的数组,用来保存堆
parent(i)
return i/2
LeftChild(i)
return 2 * i
RightChild(i)
return 2 * i + 1
SiftUp(i)
#循环方式实现while i > 1 and H[i] > H[parent(i)]: swap H[i] and H[parent(i)] i <--- parent(i)
#递归函数实现
if i > 1 and H[i] > H[parent(i)] swap H[i] and H[parent(i)] i <--- parent(i) SiftUp(i)
SiftDown(i)
#循环实现while true maxIndex <--- i l <---- LeftChild(i) if l <= size and H[l] > H[i] maxIndex <--- l r <--- RightChild(i) if r <= size and H[r] > H[maxIndex] maxIndex <--- r if i != maxIndex swap H[i] and H[maxIndex] else break
#递归函数实现
#找出该结点的较大孩子结点 maxIndex <--- i l <--- LeftChild(i) if l <= size and H[l] > H[maxIndex] maxIndex <--- l r <--- RightChild(i) if r <= size and H[r] > H[maxIndex] maxIndex <--- r if i != maxIndex swap H[i] and H[maxIndex] SiftDown(maxIndex)
Insert(p)
if size = maxSize return ERROR else size <--- size + 1 H[size] <--- p SifUp(size)
ExtractMax()
if size = 1 return ERROR else result <--- H[1] H[1] <--- H[size] size <--- size - 1 SiftDown(1) return result
remove(i)
H[i] <--- 1000000 SiftUp(i) ExtractMax()
ChangePriority(i,p)
oldp <--- H[i] H[i] <--- p if oldp > p SiftDown(i) if oldp < p SiftUp(i)
总结
实现结果:1.快速。所有操作的时间复杂度为O(log n)(GetMax()的时间复杂度甚至为O(1))
2.空间利用率高。在数组中只存储优先级,不存父母结点和孩子结点之间的连接关系
3.容易实现。所有的操作用几行代码就可以实现。
应用
使用优先级队列排序HeapSort(A)(不考虑空间使用)
1.创建一个空的优先队列2.for i from 1 to n
Insert(i)
3.for i from n downto 1
A[i] <——– ExtractMax()
上述算法的特点:
1.基于比较且时间复杂度为O(n * log n)
2.自然生成选择排序,使用良好的数据结构替代了以往扫描整个数组寻找最大数的方法
3.使用了额外的内存空间
把数组转换成堆
主要思路:从下至上的调整修正堆的性质1.首先,所有的叶子结点都是满足堆的性质的
2.然后,从深度为1的子树开始调整修正堆的性质
3.依次遍历,直到根节点时,整棵树都满足堆的性质
算法实现:(时间复杂度为n * log n)
BuildHeap(A)
size <--- n for i from n/2 downto 1 SiftDown(i)
HeapSort(A)(限制存储空间的使用)
BuildHeap(A) repeat (n - 1)times: swap A[1] and A[size] size <--- size - 1 SiftDown(1)
总结
此种堆排序和上面第一种相比,时间复杂度是相同的均为 O(n * log n),但是第二种堆排序不需要额外的内存空间
备注
以0为起始搜引号的数组:
parent(i) return (i-1)/2
LeftChild(i) return 2 * i + 1
RightChild(i) return 2 * i +2
最小二叉堆:二叉堆是每个结点值大于等于它的孩子结点值的二叉树(每个结点只有0、1或2个孩子结点)。也就是树的每一条枝上的结点值不大于它的孩子结点。
d叉堆:和二叉堆类似,不同之处在于d叉堆的每个结点的孩子结点树最多有d个,对应树的高度为O(logd n)
相关文章推荐
- UGUI组件获取及属性设置方法
- EasyUI 之 下拉框默认选择第一个选项
- UITableView使用中的一些刁专问题总结
- android 漂亮的UI集合库
- 低功耗蓝牙的连接过程
- hello word
- [置顶] UITableView
- IOS上 关于状态栏的相关设置(UIStatusBar)
- diff,patch和quilt
- [坚果原创]教你使用Arduino制作一个微型MUD聊天机器
- UITabelView 优化巧技
- junit test case和junit test suite有什么区别
- unigui数据库连接池
- new Integer(1)和Integer.valueOf(1)的区别
- 187. Repeated DNA Sequences
- UGUI自适应分辨率
- LeetCode17 17. Letter Combinations of a Phone Number My Submissions QuestionEditorial Solution
- UICollectionView 全解
- Android学习笔记十二之Android基础UI三
- BlockingQueue