数据结构与算法(堆排序)

 摘录:https://blog.csdn.net/lerry13579/article/details/82052429

 

堆排

介绍:

    堆排序也是一种选择排序。个人觉得是简单选择排序的优化,借助于二叉树这种数据结构,每趟从待排序的记录中选出关键字最小的记录,顺序放在已排序的记录序列末尾,直到全部排序结束为止。跟简单选择排序不同的是堆排序的待排序列是利用二叉树这种数据结构存储的。相比之下是更优化的。

思想:

首先,要介绍一下堆。堆是一课顺序存储的完全二叉树。有大根堆和小根堆。若每个结点的的key不小于其孩子结点的key,此时叫大根堆;若每个结点的的key不大于其孩子结点的key,此时叫小根堆。

比如,序列{k1,k2,...,kn},满足以下条件:

1.ki <= k2i+1 且 ki <= k2i+2 (小根堆)

2.ki >= k2i+1 且 ki >= k2i+2 (大根堆)

对于一个堆序列,为了方便,我们这里使用大根堆,可分为两个步骤,第一先建堆,第二把堆顶元素与最后一个元素互换位置。即最大元素输出,再把剩下的元素调整成大根堆。直到大根堆为空,则堆排序完成。

这里我举一个例子

代码:

def HeapSort(input_list):
    
    #调整parent结点为大根堆
    def HeapAdjust(input_list,parent,length):
        
        temp = input_list[parent]
        child = 2*parent+1
        
        while child < length:
            if child+1 <length and input_list[child] < input_list[child+1]:
                child +=1
            
            if temp > input_list[child]:
                break
            input_list[parent] = input_list[child]
            parent = child
            child = 2*child+1
        input_list[parent] = temp
    
    if input_list == []:
        return []
    sorted_list = input_list
    length = len(sorted_list)
    #最后一个结点的下标为length//2-1
    #建立初始大根堆
    for i in range(0,length // 2 )[::-1]:
        HeapAdjust(sorted_list,i,length)
    
    for j in range(1,length)[::-1]:
        #把堆顶元素即第一大的元素与最后一个元素互换位置
        temp = sorted_list[j]
        sorted_list[j] = sorted_list[0]
        sorted_list[0] = temp
        #换完位置之后将剩余的元素重新调整成大根堆
        HeapAdjust(sorted_list,0,j)
        print('%dth' % (length - j))
        print(sorted_list)
    return sorted_list
    
        
if __name__ == '__main__':
    input_list = [50,123,543,187,49,30,0,2,11,100]
    print("input_list:")
    print(input_list)
    sorted_list = HeapSort(input_list)
    print("sorted_list:")
    print(input_list)

结果:

 
input_list:
 
[50, 123, 543, 187, 49, 30, 0, 2, 11, 100]
 
1th
 
[187, 123, 50, 49, 100, 30, 0, 2, 11, 543]
 
2th
 
[123, 100, 50, 49, 11, 30, 0, 2, 187, 543]
 
3th
 
[100, 49, 50, 2, 11, 30, 0, 123, 187, 543]
 
4th
 
[50, 49, 30, 2, 11, 0, 100, 123, 187, 543]
 
5th
 
[49, 11, 30, 2, 0, 50, 100, 123, 187, 543]
 
6th
 
[30, 11, 0, 2, 49, 50, 100, 123, 187, 543]
 
7th
 
[11, 2, 0, 30, 49, 50, 100, 123, 187, 543]
 
8th
 
[2, 0, 11, 30, 49, 50, 100, 123, 187, 543]
 
9th
 
[0, 2, 11, 30, 49, 50, 100, 123, 187, 543]
 
sorted_list:
 
[0, 2, 11, 30, 49, 50, 100, 123, 187, 543]
 
 

分析:

1.算法性能

2.时间复杂度

时间复杂度分为两部分

第一是建立初始堆,建立堆的T(n)=O(n)

    #建立初始大根堆
    for i in range(0,length // 2 +1)[::-1]:
        HeapAdjust(sorted_list,i,length)

第二部分是排序的T(n),因为HeapAdjust()是logn,一共执行n次,故T(n)=O(nlogn)

因此总的时间复杂度为O(nlogn)

    for j in range(1,length)[::-1]:
        #把堆顶元素即第一大的元素与最后一个元素互换位置
        temp = sorted_list[j]
        sorted_list[j] = sorted_list[0]
        sorted_list[0] = temp
        #换完位置之后将剩余的元素重新调整成大根堆
        HeapAdjust(sorted_list,0,j)

3.算法稳定性

不稳定,在比较关键字和交换时会导致关键字的顺序改变。但是,堆是一种顺序存储方式,故当想求得序列中第k个最小元素之前的部分排序序列,最好采用堆排序

 

posted @ 2020-09-22 10:51  Amorphous  阅读(283)  评论(0编辑  收藏  举报