堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。
两种类型的概念如下:
大根堆(最大堆):每个结点的值都大于或等于左右孩子结点
小根堆(最小堆):每个结点的值都小于或等于左右孩子结点
以大根堆为例子:【堆是无序的】
堆的三种操作:插入,删除,构建。
假设已经存在下面的一个堆,给当前的堆添加一个节点0。【从最后一个位置,插入。顺序是:从左到右,由上到下】
最后结果为:
那么删除一个节点的话:比如在原来的堆上删除一个堆顶1.【从堆的顶部开始删除】
然后将最后一个叶子节点,调到根堆上。形成非小根堆后,进行调整为小根堆如下图:
最后:
构建二叉堆,也就是把一个无序的完全二叉树调整为二叉堆,本质上就是让所有非叶子节点依次下沉。
将一颗无序的转换成小根堆
结果:
二叉堆虽然是一颗完全二叉树,但它的存储方式并不是链式存储,而是顺序存储。换句话说,二叉堆的所有节点都存储在数组当中。
为什么堆适合采用顺序存储结构?由于堆是一棵完全二叉树,所以适宜采用顺序存储结构,这样能够充分利用存储空间。
正因为是顺序存储,使得二叉堆有更好的查询能力。假设父节点的下标是parent,那么它的左孩子下标就是 2*parent+1;它的右孩子下标就是 2*parent+2 。
因而在此基础上有了堆排序:【大根堆为例子:是一次由大根堆到小根堆的转化得到的结果。】
1. 把无序数组构建成二叉堆。
2. 循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。(实际上并不是完全删除,而是替换到最后面)
下面我们来看下堆排序的思想是怎样的(以大根堆为例):
#沿左,右子节点较大者依次往下调整 def MAX_Heapify( array, HeapSize,root ):#在堆中做结构调整使得父节点的值大于子节点 left = 2*root + 1 right = left + 1 larger = root if left < HeapSize and array[larger] < array[left]: larger = left if right < HeapSize and array[larger] <array[right]: larger = right if larger != root:#如果做了堆调整则larger的值等于左节点或者右节点的,这个时候做对调值操作 array[larger],array[root] = array[root],array[larger] MAX_Heapify(array,HeapSize,larger) #创建堆 def Build_MAX_Heap( array ):#构造一个堆,将堆中所有数据重新排序 HeapSize = len( array )#将堆的长度单独拿出来方便 for i in range( HeapSize // 2 - 1, -1, -1 ):#从后往前出数 MAX_Heapify( array,HeapSize, i) #大顶堆排序 def HeapSort( array ):#将根节点取出与最后一位做对调,对前面len-1个节点继续进行对调整过程。 Build_MAX_Heap( array ) #交换堆顶与最后一个结点,再调整堆 for i in range(len(array) - 1, -1, -1 ): array[0], array[i] = array[i], array[0] MAX_Heapify(array, i, 0) return array a = [ -3, 1, 3, 0, 9, -9, 11, 82, 7 ] print(HeapSort(a))
堆排序与快速排序的区别:
同:都是不稳定排序,两者的平均时间复杂度为nlogn
不同:在最坏的情况下:时间复杂度:前者为nlogn,后者在n^2
空间复杂度:前者为n,后者为1