堆和堆排序

堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。

两种类型的概念如下:
大根堆(最大堆):每个结点的值都大于或等于左右孩子结点
小根堆(最小堆):每个结点的值都小于或等于左右孩子结点

以大根堆为例子:【堆是无序的】

堆和堆排序_第1张图片

 

 堆的三种操作:插入,删除,构建。

假设已经存在下面的一个堆,给当前的堆添加一个节点0。【从最后一个位置,插入。顺序是:从左到右,由上到下】

堆和堆排序_第2张图片

 

 最后结果为:

堆和堆排序_第3张图片

 

 那么删除一个节点的话:比如在原来的堆上删除一个堆顶1.【从堆的顶部开始删除】

堆和堆排序_第4张图片

 

 然后将最后一个叶子节点,调到根堆上。形成非小根堆后,进行调整为小根堆如下图:

堆和堆排序_第5张图片

 

 最后:

堆和堆排序_第6张图片

 

 构建二叉堆,也就是把一个无序的完全二叉树调整为二叉堆,本质上就是让所有非叶子节点依次下沉

将一颗无序的转换成小根堆

堆和堆排序_第7张图片

 

 结果:

堆和堆排序_第8张图片

 

 

二叉堆虽然是一颗完全二叉树,但它的存储方式并不是链式存储,而是顺序存储。换句话说,二叉堆的所有节点都存储在数组当中。
为什么堆适合采用顺序存储结构?由于堆是一棵完全二叉树,所以适宜采用顺序存储结构,这样能够充分利用存储空间。

正因为是顺序存储,使得二叉堆有更好的查询能力。假设父节点的下标是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))
View Code

堆排序与快速排序的区别:

同:都是不稳定排序,两者的平均时间复杂度为nlogn

不同:在最坏的情况下:时间复杂度:前者为nlogn,后者在n^2

           空间复杂度:前者为n,后者为1

 

你可能感兴趣的:(堆和堆排序)