<HeapSort>
簡單選擇排序的改進:減少第i趟排序比較的次數。
對排序的關鍵:建堆和調整堆。
建堆的過程:
第1趟將索引0至n-1處的全部數據建大頂堆,就可以選出這組數據的最大值。將該堆的根節點跟這組數據的最后1個節點交換,就使得這組數據中最大排在了最后;
第2趟將索引0至n-2處的全部數據建大頂堆,就可以選出這組數據的最大值。將該堆的根節點與這組數據的倒數第2個節點交換,就使的這組數據中最大值排在了倒數第2位;
......
索引0至n-k處的全部數據建大頂堆,就可以選出這組數據的最大值。將該堆的根節點與這組數據的倒數第k個節點交換,就使的這組數據中最大值排在了倒數第k位。
其實整個堆排序過程中, 我們只需重復做兩件事:
建堆(初始化+調整堆, 時間復雜度為O(n));
拿堆的根節點和最后一個節點交換(siftdown, 時間復雜度為O(nlog n) )
因而堆排序整體的時間復雜度為O(nlog n)。
偽代碼:
//對下標為i的節點來說
parent(i) return i/2;
left(i) return 2*i;
right(i) return 2*i+1;
void adjust(int *a, int size,int index)
{
int left = 2*index;
int right = 2*index+1;
int parent = index/2;
int maxIndex = index;
if(left<size && a[left]>a[maxIndex]) maxIndex=left;
if(right<size && a[right]>a[maxIndex]) maxIndex=right;//maxIndex是3個數中最大數的下標
if(index != maxIndex)
{
swap(a[index],a[maxIndex]);
adjust(a,size,maxIndex); //遞歸調整其它不滿足堆性質的部分
}
}
void HeapSort(int *a,int size)
{
for(int i=size/2-1;i>=0;i--) // 對每一個非葉結點進行堆調整(從最后一個非葉結點開始)
{
adjust(a,size,i);
}
for(int i = size-1;i>=1;i--)
{
swap(a[0],a[i]);//將當前最大的放置到數組末尾;
adjust(a,i,0);
}
}