堆排序 及 优先队列
2016-07-04 10:23
337 查看
堆排序
堆分为最大堆和最小堆,其实就是完全二叉树。最大堆要求节点的元素都要大于其孩子,最小堆要求节点元素都小于其左右孩子,两者对左右孩子的大小关系不做任何要求,其实很好理解。有了上面的定义,我们可以得知,处于最大堆的根节点的元素一定是这个堆中的最大值。其实我们的堆排序算法就是抓住了堆的这一特点,每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最大堆,依次类推,最终得到排序的序列。或者说,堆排序将所有的待排序数据分为两部分,无序区和有序区。无序区也就是前面的最大堆数据,有序区是每次将堆顶元素放到最后排列而成的序列。每一次堆排序过程都是有序区元素个数增加,无序区元素个数减少的过程。当无序区元素个数为1时,堆排序就完成了。本质上讲,堆排序是一种选择排序,每次都选择堆中最大的元素进行排序。只不过堆排序选择元素的方法更为先进,时间复杂度更低,效率更高。图例说明一下:(图片来自http://www.cnblogs.com/zabery/archive/2011/07/26/2117103.html)具体步骤如下: 1 首先从第一个非叶子节点开始,比较当前节点和其孩子节点,将最大的元素放在当前节点,交换当前节点和最大节点元素。 2 将当前元素前面所有的元素都进行1的过程,这样就生成了最大堆 3 将堆顶元素和最后一个元素交换,列表长度减1。由此无序区减1,有序区加1 4 剩余元素重新调整建堆 5 继续3和4,直到所有元素都完成排序堆的应用:优先队列
优先队列(priority queue)实际上也是由堆来实现,所以有最大优先队列和最小优先队列两种。优先队列的其中一个应用就是在共享计算机系统的作业调度。最大优先队列记录将要指定的各个作业及它们之间的相对优先级。当一个作业完成或者被中断后,调度器调用extract
从所有的等待作业中,选出具有最高优先级的作业来执行。在任何时候,调度器可以调用insert
把一个新作业加入到队列中来。
最小优先队列可以诶用于基于事件驱动的模拟器,队列中保存要模拟的事件,每个事件都有一个发生时间作为其关键字。事件必须按照发生的时间顺序模拟,而某一事件的模拟结果可能会触发其他事件。模拟程序调用extract来选择下一个要模拟的事件,当一个新事件产生时,模拟程序调用
insert将其插入最小优先队列中。下面就是利用堆实现优先队列的代码:
class priQueue:heap = []last = 0def __init__(self, num):self.heap = numself.last = len(self.heap) - 1# print self.heap[1:]def HeapAdjust(self, i, last):minIndx = ileft = i * 2right = i * 2 + 1if i <= last / 2:if left <= last and self.heap[minIndx] > self.heap[left]: # has left childminIndx = leftif right <= last and self.heap[minIndx] > self.heap[right]: # has right childminIndx = rightif i != minIndx:self.swap(i, minIndx)self.HeapAdjust(minIndx, last)def HeapBuild(self):i = self.last / 2while i > 0:self.swap(1, i)self.HeapAdjust(i, self.last)i = i - 1def HeapSort(self):i = self.lastwhile i > 1:self.swap(1, i) # has order# print self.heap[1:]self.HeapAdjust(1, i - 1)i = i - 1def swap(self, i, j):if i != j:temp = self.heap[i]self.heap[i] = self.heap[j]self.heap[j] = tempdef insert(self, val):self.heap.append(val)self.last = self.last + 1print "insert heap: ", self.heap[1:]self.insertInto(val, self.last)def insertInto(self, val, last):i = lastp = i / 2while p >= 1 and self.heap[i] < self.heap[p]:self.swap(i, p)i = pp = i / 2def extract(self):self.swap(1, self.last)res = self.heap.pop()self.last = self.last - 1self.HeapAdjust(1, self.last)return resif __name__ == "__main__":Heap = [0, 49, 38, 65, 97, 76, 13, 27, 49]print "orginal heap:",Heap[1:]qq = priQueue(Heap)qq.HeapBuild()print "build heap:", Heap[1:]print qq.extract()print "extract heap:", Heap[1:]qq.insert(13)print "insert adjust heap:", Heap[1:]qq.HeapSort()print "heap sort: ", Heap[1:]
堆排序和快速排序的比较
尽管堆排序和快速排序都是O(nlogn)O(nlogn)的排序算法,但这只是算法渐近的趋势,实际上它们的性能(主要表现在常数因子上)还是有一些区别的。下表给出了快速排序、堆排序和插入排序比较次数和交换次数的对比:(数据来自ComparingQuick and Heap Sorts)相关文章推荐
- 欢迎使用CSDN-markdown编辑器
- Ubuntu 12.04 图形界面问题解决 开机死机
- Android开发之HTTP访问网络
- 二分查找法 java
- Win7&Win8IE11浏览器安装成功但是不能打开
- 团体程序设计天梯赛-练习集L1-012. 计算指数
- web 与 app 共用接口
- 这些糟心简历,HR不要看!
- Android四大组件之Service精通
- linux后台开发具备能力集锦
- Mac AppStore下载文件的获取
- java基础语言写简单计算器
- Android View系统源码分析(八)—— View.onFocusedChanged()
- android 正则表达式
- CUDA代码不同平台编译问题
- jquery事件有关问题!对象 click和document click冲突有关问题
- 从哈密尔顿路径谈NP问题
- 参数传递中的编码问题(get和post方式)
- tomcat源码编写计划连载(1)
- win2012卸载.netframework4.5 黑屏修复