天天看點

算法導論讀書筆記(6)堆排序第二部分 排序和順序統計量

第二部分 排序和順序統計量

第6章 堆排序

  1. 複雜度O(nlgn)
  2. 原址排序
  3. 集插入排序和歸并排序兩者的優點

1. 堆

  • 堆是一個數組,可看成一個近似的完全二叉樹
  • 除了最底層外,該樹是完全充滿的
  • 從左向右填充
  • 堆的高度 = 根結點的高度
  • 堆結構上一些基本操作的運作時間至多與樹的高度成正比,即時間複雜度為O(lgn)

    表示堆的數組A包括兩個屬性

    1. A.length給出數組中元素的個數
    2. A.heap-size表示有多少個堆元素存儲在該數組中
算法導論讀書筆記(6)堆排序第二部分 排序和順序統計量

計算給定節點下标i的父,左孩子,右孩子的下标

Parent(i) return i/2 Left(i) return 2i Right(i) return 2i + 1

最大堆(堆中最大元素存放在根結點)

  • A[Parent(i)] >= A[i]

最小堆(堆中最小元素存放在根結點)

  • A[Parent(i)] <= A[i]
  • 通過用過構造優先隊列

2. 維護堆的性質

算法導論讀書筆記(6)堆排序第二部分 排序和順序統計量

從A[i]、A[Left(i)]和A[Right(i)]中選出最大的,并将下标存儲在largest中。如果A[i]是最大的,程式結束。否則,最大元素是i的某個孩子結點,則交換A[i]和A[largest]的值,進而使i及其孩子都滿足最大堆的性質。在交換後,下标為largest的結點的值是原來的A[i],于是以該結點為根的子樹又可能會違反最大堆的性質,是以,需要對孩子樹遞歸調用Max-heapify

Max-Heapify(A, i)
    l = Left(i)
    r = Right(i)

    if l <= A.heap-size and A[l] > A[i]
        largest = l
    else
        largest = i
    if r <= A.heap-size and A[r] > A[largest]
        largest = r

    if largest != i
        exchange A[i] with A[largest]
        Max-Heapify(A, largest)
           

Max-heapify的時間複雜度為O(h), h = 樹高。

當用數組存儲n個元素的堆時,葉結點下标分别是⌊n/2⌋+1, ⌊n/2⌋+2, …, n.

3. 建堆

算法導論讀書筆記(6)堆排序第二部分 排序和順序統計量

用自底向上的方法利用過程Max-heapify把一個大小為n = A.length的數組A[1..n]轉換為最大堆。

Build-Max-Heap(A)
    A.heap-size = A.length
    for i = ⌊A.length/⌋ downto 
        Max-Heapify(A, i)
           

每次調用Max-Heapify的時間複雜度是O(lgn),Build-Max-Heap需要O(n)次這樣的調用。是以總的時間複雜度是O(nlgn)。這個上界雖然正确,但不是漸近緊确。

4. 堆排序

算法導論讀書筆記(6)堆排序第二部分 排序和順序統計量

先建成最大堆,因數組中最大的元素在根結點A[1],通過把它與A[n]互換,可以儲存最大的元素并從堆中去掉結點n,剩餘的結點中,原來根的孩子結點仍然是最大堆,而新的根結點可能會違背最大堆的性質,是以需要調用Max-Heapify(A, 1)構造一個新的最大堆,不斷重複這一過程,直到堆的大小降到2。

Heapsort(A)
    Build-Max-Heap(A)
    for i = A.length downto 
    exchange A[] with A[i]
    A.heap-size = A.heap-size - 
    Max-Heapify(A, )
           

時間複雜度O(nlgn)

5. 優先隊列(用堆實作)

優先隊列有兩種形式

1. 最大優先隊列

2. 最小優先隊列,可被用于基于事件驅動的模拟器。隊列中儲存要模拟的事件,每個事件都有一個發生時間作為其關鍵字。事件必須按照發生的時間順序進行模拟,因為某一事件的模拟結果可能會觸發對其他事件的模拟

Heap-Maximum(A)
    return A[]
           
Heap-Extract-Max(A)
    if A.heap-size < 
        error "heap underflow"
    max = A[]
    A[] = A[A.heap-size]
    Max-Heapify(A, )
    return max
           
算法導論讀書筆記(6)堆排序第二部分 排序和順序統計量
修改關鍵字的大小後,目前元素會不斷地與其父結點進行比較,如果目前元素的關鍵字較大,則目前元素與其父結點進行交換。不斷重複該過程,直到目前元素的關鍵字小于其父結點時終止。

Heap-Increase-Key(A, i, key)
    if key < A[i]
        error "new key is smaller than currenty key"
    A[i] = key
    while i >  and A[Parent(i)] < A[i]
        exchange A[i] with A[Parent(i)]
        i = Parent(i)
           
首先增加一個葉結點來擴充最大堆,然後調用Heap-Increase-Key為新結點設定對應的關鍵字,同時儲存最大堆的性質

Max-Heap-Insert(A, key)
    A.heap-size = A.heap-size + 
    A[A.heap-size] = 
    Heap-Increase-Key(A, A.heap-size, key)
           

繼續閱讀