堆排序,C++模板編程


明天就要去參加百度的筆試了,現在來抱抱佛教。

 

理論來自:簡明現代魔法

在程序設計相關領域,堆(Heap)的概念主要涉及到兩個方面:

  • 一種數據結構,邏輯上是一顆完全二叉樹,存儲上是一個數組對象(二叉堆)。
  • 垃圾收集存儲區,是軟件系統可以編程的內存區域。

本文所說的堆,指的是前者。

堆排序的時間復雜度是O(nlgN),與快速排序達到相同的時間復雜度。但是在實際應用中,我們往往采用快速排序而不是堆排序。這是因為快速排序的一個好的實現,往往比堆排序具有更好的表現。堆排序的主要用途,是在形成和處理優先級隊列方面。另外,如果計算要求是類優先級隊列(比如,只要返回最大或者最小元素,只有有限的插入要求等),堆同樣是很適合的數據結構。

基礎知識

堆一般用數組表示,比如數組A數組的長度Length(A),堆在數組中的元素個數HeapSize(A)。一般說來,HeapSize(A) <= Length(A),因為數組A當中可能有一些元素不在堆中。

假設節點I是數組A中下標為i的節點。

  • Parent(i) : return Floor(i/2); //I的父節點下標,Floor(i)表示比i小的最大整數。
  • Left(i) : return 2*i; //I的左子節點
  • Right(i) : return 2*i+1; //I的右子節點

含有n個元素的堆A的高度是: Floor(lgn)。

堆的基本操作
  • MaxHeapify( A, i ):

    保持堆的性質。假設數組A和下標i,假定以Left(i)和Right(i)為根結點的左右兩棵子樹都已經是最大堆,節點i的值可能小於其子節點。調整節點i的位置。

  • BuildMaxHeap( A ):

    從一個給定的數組建立最大堆。子數組A[ floor(n/2)+1 .... ... n]中的元素都是樹的葉節點(完全二叉樹的基本性質)。從索引 ceiling(n/2)開始一直到1,對每一個元素都執行MaxHeapify,最終得到一個最大堆。

  • 堆排序 HeapSort( A ):

    堆排序算法的基本思想是,將數組A創建為一個最大堆,然后交換堆的根(最大元素)和最后一個葉節點x,將x從堆中去掉形成新的堆A1,然后重復以上動作,直到堆中只有一個節點。

  • 優先級隊列算法-增加某元素的值(優先級) : HeapIncreaseKey( A, i, key )

    增加某一個元素的優先級后(元素的值),該元素應該向上移動,才能保持堆的性質。

  • 優先級隊列算法-插入一個元素: Insert( S, x ) 將x元素插入到優先級隊列S中。

    主要思路是,將堆的最后一個葉節點之后,擴展一個為無窮小的新葉節點,然后增大它的值為x的值。

 

本來我只打算隨便寫個小程序的,但是發現,可以寫個更通用的程序。以最小堆為例,說下建堆和排序的過程。

heapSort_1

heapSort_2

經過上面兩個步驟,就成功的建立了一個最小堆。排序的過程就是取出堆頂元素push到臨時數組,然后將堆頂元素和最后一個元素交換,再pop掉最后一個元素,直到堆中沒有元素。這樣就獲得了一個有序的數組,然后在復制到堆中。

完整程序如下:

//最小堆排序和最大堆排序

#include <algorithm>
#include <functional>
#include <vector>
#include <iostream>
using namespace std;

template<typename Type>
class Heap
{
public:
    Heap(const vector<Type>& a_array)
    {
        m_array.assign(a_array.begin(),a_array.end());
    }

    template<typename Compare>
    void sort(Compare comp);

    void printArray(const vector<Type>& a_array);

private:
    vector<Type> m_array;

    //comp 為less<Type> 則大數下沉,創建最小堆,從小到大排序
    //comp 為greater<Type> 則小數下沉,創建最大堆,從大到小排序
    template<typename Compare>
    void creatHeap(Compare comp);                //創建堆

    template<typename Compare>
    void downElement(int a_elem, Compare comp);    //下沉元素
};

template<typename Type>
template<typename Compare>
void Heap<Type>::sort(Compare comp)
{
    printArray(m_array);
    creatHeap(comp);                    //建堆
    vector<Type> array;
    for (int i = m_array.size() - 1; i >= 0; i--)
    {
        array.push_back(m_array[0]);    //保留堆頂
        swap(m_array[0], m_array[i]);    //交換
        m_array.pop_back();                //去掉最后一個元素
        downElement(0,comp);            //將新的首元素下沉
    }
    printArray(array);
    m_array.assign(array.begin(),array.end());
}

template<typename Type>
template<typename Compare>
void Heap<Type>::creatHeap(Compare comp)
{
    //從最后一個非葉子節點開始,將每個父節點都調整為最小堆
    for (int i=m_array.size()/2-1; i>=0; i--)
    {
        downElement(i, comp);
    }
}

template<typename Type>
template<typename Compare>
void Heap<Type>::downElement(int a_elem, Compare comp)    //下沉元素
{
    int min;            //設置最小元素下標
    int index = a_elem;    //當前下沉的元素下標
    while (index*2+1 < m_array.size())//存在左節點
    {
        min = index*2+1;
        if (index*2+2 < m_array.size())//存在右節點
        {
            //左右節點比較,選出最小的
            if (comp(m_array[index*2+2],m_array[min]))
            {
                min = index*2+2;
            }
        }
        //同子節點比較,若父節點最小則結束
        if (comp(m_array[index],m_array[min]))
        {
            break;
        }
        else//選最小元素到父節點
        {
            swap(m_array[min],m_array[index]);
            index = min;
        }
    }
}

template<typename Type>
void Heap<Type>::printArray(const vector<Type>& a_array)
{
    for (int i=0; i<a_array.size(); i++)
    {
        cout << a_array[i] << " ";
    }
    cout << endl;
}


int main()
{
    vector<int> array;
    for (int i=10; i<20; i++)
    {
        array.push_back(i);
    }
    random_shuffle(array.begin(), array.end());//打亂順序
    Heap<int> heap(array);
    heap.sort(less<int>());
    heap.sort(greater<int>());
    return 0;
}

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM