1. 程式人生 > >資料結構--二叉堆與堆排序

資料結構--二叉堆與堆排序

  • 二叉堆的概念

二叉堆,BinaryHeap,是二叉樹中的常見的一種結構。通常以最大堆和最小堆的形式呈現。最大堆指的是父節點大於等於孩子節點的value值,也就是說對於最大堆而言,根元素是二叉堆最大的元素。最小堆的概念是與最大堆的概念是相似的。下圖是最大堆的示意圖:

  • 二叉堆和排序之間的聯絡

二叉堆最顯著的特徵就是根元素是二叉樹元素間最大的或者最小的。因此每次將二叉樹最大或者最小的元素取出來,同時保證每次進行這樣的操作後,剩下的元素依然可以保持二叉堆的性質,這樣迭代這個過程,就可以完成排序的目的。

所以,進行堆排序的過程,首先就需要進行待排序元素的堆建立過程。這裡以最大堆為例。

堆的建立過程

在建立最大堆的過程中,每插入一個元素,就要對元素進行一個上浮的操作。上浮是指對每個即將插入最大堆的元素進行判斷,判斷與當前元素與其父元素的大小關係,保持父元素與孩子元素之間的大小關係,重複這個過程,直到從根元素開始,所有的父元素和孩子元素都和二叉堆的定義保持一致。具體實現過程如下:

首先是最大堆的ADT:

template<class T>
class BinaryHeap
{
public:
    BinaryHeap(int capacity);
    ~BinaryHeap();

    void filterUp(int start);
    void Insert(T &data);


    T delHeap();

    void BuildHeap(vector<T> initArray);
    void displayHeap();

private:
    T *m_pData;
    int mCurSize;
    int mCapacity;
};
然後是最大堆的建立過程:
template<class T>
void BinaryHeap<T>::filterUp(int start)
{

    int nIndex=start;
    T temp=m_pData[nIndex];
    int parentIndex=(int) start/2;

    while(nIndex>0)
    {
        if(m_pData[parentIndex]<temp)
        {
            m_pData[nIndex]=m_pData[parentIndex];
            nIndex=parentIndex;
            parentIndex=(int) nIndex/2;
        }
        else
            break;
    }
    m_pData[nIndex]=temp;

}

template<class T>
void BinaryHeap<T>::Insert(T &data)
{
    if(mCurSize>=mCapacity)
    {
        mCapacity*=2;
        mCurSize++;
    }
    m_pData[mCurSize]=data;
    filterUp(mCurSize);
}

完成了最大堆的建立,就可以進行最大元素的抽取了,將抽取的元素存起來,就可以進行迭代過程的排序了:

這裡在抽取最大元素的抽取後,相應的元素個數就會減少一個,如果是把根元素的孩子結點移動到根元素的位置,然後從上往下進行這樣的移動,這樣不能很好的保持完全二叉樹的性質。因此這裡採取的小技巧是,將二叉樹的最後一個元素移動到根元素的位置,這樣僅僅只是交換value值,不需要頻繁的移動元素的位置。以下是該過程的示意圖:

第一步:



第二步:



這樣就完成了最大元素的抽取過程了,然後下面是具體的實現過程:

template<class T>
T BinaryHeap<T>::delHeap()
{
    int parentIndex=0;
    T tempMax=m_pData[parentIndex];
    int nIndex=parentIndex*2+1;

    m_pData[parentIndex]=m_pData[mCurSize-1];
    T tempCur=m_pData[parentIndex];
    while((nIndex+1)<mCurSize)
    {

        if(tempCur>=m_pData[nIndex] && tempCur>=m_pData[nIndex+1])
        {

            break;
        }
        else
        {
            if(m_pData[nIndex]>m_pData[nIndex+1])
                {
                    m_pData[parentIndex]=m_pData[nIndex];
                    parentIndex=nIndex;
                }
            else
                {
                     m_pData[parentIndex]=m_pData[nIndex+1];
                     parentIndex=nIndex+1;
                }

                     nIndex=2*parentIndex+1;
        }
    }
    m_pData[parentIndex]=tempCur;
    if(mCurSize>1)
        mCurSize--;
    else
    {
        mCurSize--;
        cout<<"the heap size is zero!"<<endl;
    }
    return tempMax;

}

以上就是關鍵的過程的程式碼,下面是完整過程的程式碼:

首先是二叉堆的標頭檔案:

#ifndef BINARYHEAP_H_INCLUDED
#define BINARYHEAP_H_INCLUDED

#include<vector>
#include<queue>
#include<iostream>
using namespace std;
template<class T>
class BinaryHeap
{
public:
    BinaryHeap(int capacity);
    ~BinaryHeap();

    void filterUp(int start);
    void Insert(T &data);


    T delHeap();

    void BuildHeap(vector<T> initArray);
    void displayHeap();

private:
    T *m_pData;
    int mCurSize;
    int mCapacity;
};


template<class T>
BinaryHeap<T>::BinaryHeap(int capacity)
{
    mCurSize=0;
    mCapacity=capacity;
    m_pData=new T[capacity];
}

template<class T>
BinaryHeap<T>::~BinaryHeap()
{
    mCurSize=0;
    mCapacity=0;
    delete []m_pData;
}

template<class T>
void BinaryHeap<T>::filterUp(int start)
{

    int nIndex=start;
    T temp=m_pData[nIndex];
    int parentIndex=(int) start/2;

    while(nIndex>0)
    {
        if(m_pData[parentIndex]<temp)
        {
            m_pData[nIndex]=m_pData[parentIndex];
            nIndex=parentIndex;
            parentIndex=(int) nIndex/2;
        }
        else
            break;
    }
    m_pData[nIndex]=temp;

}

template<class T>
void BinaryHeap<T>::Insert(T &data)
{
    if(mCurSize>=mCapacity)
    {
        mCapacity*=2;
        mCurSize++;
    }
    m_pData[mCurSize]=data;
    filterUp(mCurSize);
}

template<class T>
void BinaryHeap<T>::BuildHeap(vector<T> initArray)
{
    int nSize=initArray.size();
    if(nSize==0)
        return;
    else
    {
        for(int i=0;i<nSize;i++)
        {
            Insert(initArray.at(i));
            if(mCurSize<mCapacity)
                mCurSize++;
            else
            {
                mCapacity*=2;
                mCurSize++;
            }
        }

    }
}

template<class T>
T BinaryHeap<T>::delHeap()
{
    int parentIndex=0;
    T tempMax=m_pData[parentIndex];
    int nIndex=parentIndex*2+1;

    m_pData[parentIndex]=m_pData[mCurSize-1];
    T tempCur=m_pData[parentIndex];
    while((nIndex+1)<mCurSize)
    {

        if(tempCur>=m_pData[nIndex] && tempCur>=m_pData[nIndex+1])
        {

            break;
        }
        else
        {
            if(m_pData[nIndex]>m_pData[nIndex+1])
                {
                    m_pData[parentIndex]=m_pData[nIndex];
                    parentIndex=nIndex;
                }
            else
                {
                     m_pData[parentIndex]=m_pData[nIndex+1];
                     parentIndex=nIndex+1;
                }

                     nIndex=2*parentIndex+1;
        }
    }
    m_pData[parentIndex]=tempCur;
    if(mCurSize>1)
        mCurSize--;
    else
    {
        mCurSize--;
        cout<<"the heap size is zero!"<<endl;
    }
    return tempMax;

}

template<class T>
void BinaryHeap<T>::displayHeap()
{
    for(int i=0;i<mCurSize;i++)
    {
        cout<<m_pData[i]<<"---";
    }
    cout<<endl;
}



#endif // BINARYHEAP_H_INCLUDED
然後是主過程的呼叫,在主過程完成排序:
#include <iostream>
#include<cstdlib>
#include<ctime>
#include"BinaryHeap.h"

using namespace std;

int main()
{
    srand(unsigned(time(NULL)));

    vector<int> initArray;
    int data=rand()%100;
    int length=rand()%15;
    int cnt=0;
    while(cnt<length)
    {
        initArray.push_back(data);
        data=rand()%100;
        cnt++;
    }

    cout<<"待排序序列:"<<endl;
    for(int i=0;i<length;i++)
        cout<<initArray.at(i)<<"---";
    cout<<endl;

    BinaryHeap<int> heap(30);
    heap.BuildHeap(initArray);
    cout<<"建立好的最大堆:"<<endl;
    heap.displayHeap();

    int maxEle;
    vector<int> sortedArray;
    for(int i=0;i<initArray.size();i++)
    {
        maxEle=heap.delHeap();
        sortedArray.push_back(maxEle);

    }

    cout<<"排序完成的序列:"<<endl;
    for(int i=0;i<sortedArray.size();i++)
    {
        cout<<sortedArray.at(i)<<"---";
    }
        cout<<endl;
    cout << "Hello world!" << endl;
    return 0;
}
然後結果如下: