堆排序

Posted a-runner

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆排序相关的知识,希望对你有一定的参考价值。

1 堆

  堆是一个二叉堆的数组,可以被看成一个近似的完全二叉树。

  有最大堆和最小堆的性质。最大堆就是某个节点的值至多于其父节点一样大。最小堆中最小的元素都存放在根节点中。

下面放上最小堆的伪代码:

MIN-HEAPIFY(A, i)
l = LEFT(i)
r = RIGHT(i)
if l <= A.heap-size and A[l] < A[i]
    smallest = l
else smallest = i
if r <= A.heap-size and A[r] < A[smallest]
    smallest = r
if smallest !=i
    exchange A[i] with A[smallest]
    MIN-HEAPIFY(A, smallest)

 

2 建堆

  建堆 ,采用紫霞而上的方法。每个节点的左右孩子节点都是最大堆。

BUILD-MAX-HEAP(A):
    A.heap-size = A.length;
    //heap-size代表整个数组中在堆中的元素个数
    for i = A.length/2 downto 1:
        MAX-HEAPIFY(i)

3 堆排序算法

  因为,建堆之后,堆的根节点是整个数的最大节点,可以提取出来,在堆剩下的数进行建堆的处理。

  我们从A.length到2循环调用,直到堆的元素只有两个。

HEAP-SORT(A):
    BUILD-MAX-HEAP(A);     //构建最大堆
    for i = A.length downto 2:
        exchange A[i] and A[1];
        A.heap-size = A.heap-size-1;
        MAX-HEAPIFY(i); # 此后的左右子树都是最大堆

  MAX-HEAPIFY的时间复杂度:

写出递归式: T(n)<=T(2n/3) + 1, 根据主方法确定时间复杂度为 log(n)。

  时间复杂度为nlog(n).因为内次调用MAX-HEAPIFY的时间复杂度为log(n),进行n-1次循环。

  对于按升序排列包含n个元素的有序数组来A说,HEAPSORT的时间复杂度为nlog(n),降序排列也一样。在SORT中,首先执行一次的BUILD,复杂度为n,之后进行(n-1)次MAX-HEAPIFY,进行递归的调用。

4 优先序列

  有限队列是一种用来维护由一组元素构成的集合S的数据结构,每一个元素都有一个相关的值,称为关键字,key。

附上相关代码:

import math

class Stack():
    def __init__(self, a):
        self.a = a
        self.length = len(a)-1
        self.heap_size = len(a)-1

    def left(self, i):
        if 2 * i <= self.heap_size:
            return 2*i
        else:
            return None

    def right(self, i):
        if (2 * i + 1) <= self.heap_size:
            return (2*i+1)
        else:
            return None

    def parent(self,i):
        return math.floor(i/2)

    def max_heapify(self, i):
        l = self.left(i)
        r = self.right(i)
        largest = 0
        if  l:
            if self.a[l]>self.a[i]:
                largest = l
            else:
                largest = i
        if  r:
            if self.a[r]>self.a[largest]:
                largest = r
        if largest!=i and largest!=0:
            self.a[i], self.a[largest] = self.a[largest], self.a[i]
            self.max_heapify(largest)

    def build_max_heap(self):
        for i in range(math.floor(self.length/2),0,-1):
            self.max_heapify(i)

    # 对最大堆进行排序
    def heap_sort(self):
        self.build_max_heap()
        for i in range(self.length,1,-1):
            self.a[i],self.a[1] = self.a[1],self.a[i]
            self.heap_size -= 1
            self.max_heapify(1)

    def sorted(self):
        print(升序排列的 最大堆元素(0除外):)
        for i in self.a:
            print(i,end= )
            
    # 返回当前具有最大关键字的元素的值(下一个要执行的优先级)
    def heap_maximum(self):
        return self.a[1]

    # 去掉并返回a中具有最大键子的元素
    def heap_extract_max(self):
        if self.heap_size <1:
            print(heap underflow)
            raise
        max = self.a[1]
        self.a[1] = self.a[self.heap_size]
        self.heap_size -=1
        self.max_heapify(1)
        return max

    # 改变某元素的关键字,增加到k,重新构建最大堆
    def heap_increase_key(self,i,key):
        if key<self.a[i]:
            print(new key is smaller than current key)
            raise
        self.a[i] = key
        while i>1 and self.a[self.parent(i)]<self.a[i]:
            self.a[i],self.a[self.parent(i)] = self.a[self.parent(i)],self.a[i]
            i = self.parent(i)

    def max_heap_insert(self, key):
        self.heap_size += 1
        self.a[self.heap_size] = 0
        self.heap_increase_key(self.heap_size,key)

if __name__ == __main__:
    b = [0,3,8,5,6,1,32,13,18]
    a = Stack(b)
    a.heap_sort()
    a.sorted()

 

 

  对于优先队列的操作有:插入,改变优先级等。在包含n个元素的堆中,所有优先队列的操作都可以在log(n)时间内完成。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

将k个有序列表合并为一个有序列表,这里的n是所有输入链表包含的总的元素的个数。大致思路为:

K路归并算法了,思想是将每个链表的第一个元素提取出来,初始化成一个最小堆,然后取出该最小堆中的第一个元素就是根节点,该节点的data便是最小的,然后将该节点插入到新的单链表中;插入完成后,这个根节点所在的链表的下一个元素,将该元素替代原来根节点在最小堆中的位置然后最小堆化根节点,然后取新最小化的最小堆的根节点,插入到新的链表中。如果某个链表取完后,则将最小堆的第一个元素和最后一个元素对换一下,再最小堆化一下,同时堆的大小减1;最后,当最小堆的大小为0时,新的归并后的链表也就完成了。
时间复杂度:因为有k个链表,总共有n个元素,因此发生了n次的最小堆化,时间复杂度为O(nlgk)
详情可参考:

以上是关于堆排序的主要内容,如果未能解决你的问题,请参考以下文章

选择排序(简单选择排序堆排序的算法思想及代码实现)

排序--08---堆排序

python代码实现堆排序

算法-java代码实现堆排序

一文带你了解堆排序

堆排序