資料結構--二叉堆與堆排序
阿新 • • 發佈:2019-01-23
- 二叉堆的概念
二叉堆,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;
}
然後結果如下: