您的位置:首页 > 其它

堆排序 及 优先队列

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(nlog⁡n)的排序算法,但这只是算法渐近的趋势,实际上它们的性能(主要表现在常数因子上)还是有一些区别的。下表给出了快速排序、堆排序和插入排序比较次数和交换次数的对比:(数据来自ComparingQuick and Heap Sorts)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: