#pragma once
#include
#include
#include
using namespace std;
template
class Heap
{
public:
Heap()
:_a(NULL)
{}
Heap(const T* a,size_t size)
{
assert(a);
for(size_t i=0;i0;--i)
{
_AdjustDown(i);
}
}
void Push(const T& x)
{
_a.push_back(x);
_AjustUp(_a.size()-1);
}
void Pop()
{
assert(_a.empty());
swap(_a[0],_a[a.size()-1]);
_AdjustDown();
}
protected:
void _AdjustDown(size_t parent)
{
size_t child = parent*2+1;
while(child > 0)
{
if(_a[child] < _a[child+1] && child<_a.size())
{
++child;//如果左孩子比有孩子大的話,不做處理,反之,使得大的變成child = child+1;
}
if(_a[child]>_a[parent]) //每次交再向下調(diào)整
{
swap(_a[child],_a[parent]);
parent = child;
child = parent*2+1;
}
else
{
break;
}
}
}
void _AjustUp(size_t child)
{
int parent = (child-1)/2;
while(child > 0) //這里必須判斷孩子下標,否則很危險。如果要用父親的判斷,則應(yīng)該把size_t改為int
{
if(_a[parent]<_a[child])
{
swap(_a[parent],_a[child]);
child = parent;
parent = (child-1)/2;
}
else
{
break;
}
}
}
protected:
vector _a;
};
void TestHeap()
{
int a[] = {10,11,13,12,16,18,15,17,14,19};
Heap Hp1(a,sizeof(a)/sizeof(a[0]));
Hp1.Push(20);
}
int main()
{
TestHeap();
system( "pause");
return 0;
}
2.堆排序思想
利用大根堆小根堆堆頂元素是最大記錄(最小記錄),使得每次從無序中選擇最大(最小記錄)就變得簡單了。這里采用大根堆思想,
1)將初始待排序關(guān)鍵字序列(R1,R2....Rn)構(gòu)建成大頂堆,此堆為初始的無序區(qū);
2)將堆頂元素R[1]與最后一個元素R[n]交換,此時得到新的無序區(qū)(R1,R2,......Rn-1)和新的有序區(qū)(Rn),且滿足R[1,2...n-1]<=R[n];
3)由于交換后新的堆頂R[1]可能違反堆的性質(zhì),因此需要對當前無序區(qū)(R1,R2,......Rn-1)調(diào)整為新堆,然后再次將R[1]與無序區(qū)最
后一個元素交換,得到新的無序區(qū)(R1,R2....Rn-2)和新的有序區(qū)(Rn-1,Rn)。不斷重復(fù)此過程直到有序區(qū)的元素個數(shù)為n-1,則整個排
序過程完成。
//堆排序
#include
#include
using namespace std;
void AjustDown(int a[],size_t n,int parent)
{
assert(a);
int child = parent*2+1;
while(childa[parent])
{
swap(a[child],a[parent]);
parent = child;
}
else
{
break;
}
}
}
void HeapSort(int a[],size_t n)
{
assert(a);
for(int i=(n-2)/2;i>0;--i)
{
AjustDown(a,n,i);
}
for(int i = 0; i < n; ++i)
{
swap(a[0],a[n-i-1]);
AjustDown(a,n-i-1,0);
}
}
void Test()
{
int a[]={2,1,4,3,5,6,0,4,7,8,9};
HeapSort(a,sizeof(a)/sizeof(a[0]));
}
int main()
{
Test();
system("pause");
return 0;
}
算法分析:
從上述過程可知,堆排序其實也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從R[1...n]中選擇最大記錄,需比較n-1次,然后
從R[1...n-2]中選擇最大記錄需比較n-2次。事實上這n-2次比較中有很多已經(jīng)在前面的n-1次比較中已經(jīng)做過,而樹形選擇排序恰好利用樹形的
特點保存了部分前面的比較結(jié)果,因此可以減少比較次數(shù)。對于n個關(guān)鍵字序列,最壞情況下每個節(jié)點需比較log2(n)次,因此其最壞情況下時間復(fù)雜度為
nlogn。堆排序為不穩(wěn)定排序,不適合記錄較少的排序。
3.堆的應(yīng)用
例:100W個數(shù)中找出最大的100個
1 小根堆;
2 堆固定大小為100;
3 堆元素個數(shù)小于100時直接加入堆;
4 堆元素個數(shù)等于100時,與堆頂元素比較,比堆頂元素大的進堆,并調(diào)整堆;
5 遍歷結(jié)束時,堆中元素為100個最大數(shù)。
#pragma once
#include
#include
#include
#include
using namespace std;
const int N = 10000;
const int K = 100;
void _AjustDown(int TopK[],int size,int parent)
{
assert(TopK);
int child = parent*2+1;
while( child < size)
{
if(child < size && (TopK[child] < TopK[child+1]))
{
++child;
}
if(TopK[child] > TopK[parent])
{
swap(TopK[child],TopK[parent]);
parent = child;
}
else
{
break;
}
}
}
void GetTop(int a[])
{
assert(K < N);
int TopK[K];
for(int i=0;i= 0;--i)
{
_AjustDown(TopK,K,0);
}
for(int i=0;i
當前文章:堆的創(chuàng)建&堆排序&堆的應(yīng)用
分享鏈接:http://weahome.cn/article/iegddo.html