問題 A: 算法10-10,10-11:堆排序
時間限制: 1 Sec 內存限制: 32 MB
提交: 160 解決: 119
[提交][狀態][討論版][命題人:外部導入]
題目描述
堆排序是一種利用堆結構進行排序的方法,它只需要一個記錄大小的輔助空間,每個待排序的記錄僅需要佔用一個存儲空間。
首先建立小根堆或大根堆,然後通過利用堆的性質即堆頂的元素是最小或最大值,從而依次得出每一個元素的位置。
堆排序的算法可以描述如下:
在本題中,讀入一串整數,將其使用以上描述的堆排序的方法從小到大排序,並輸出。
輸入
輸入的第一行包含1個正整數n,表示共有n個整數需要參與排序。其中n不超過100000。
第二行包含n個用空格隔開的正整數,表示n個需要排序的整數。
輸出
只有1行,包含n個整數,表示從小到大排序完畢的所有整數。
請在每個整數後輸出一個空格,並請注意行尾輸出換行。
樣例輸入
10
2 8 4 6 1 10 7 3 5 9
樣例輸出
1 2 3 4 5 6 7 8 9 10
提示
在本題中,需要按照題目描述中的算法完成堆排序的算法。
堆排序對於元素數較多的情況是非常有效的。通過對算法的分析,不難發現在建立含有n個元素的堆時,總共進行的關鍵字比較次數不會超過4n,且n個節點的堆深度是log2n數量級的。因此,堆排序在最壞情況下的時間複雜度是O(nlog2n),相對於快速排序,堆排序具有同樣的時間複雜度級別,但是其不會退化。堆排序較快速排序的劣勢是其常數相對較大。
#include<stdio.h>
#include<algorithm>
using namespace std;
/*
堆是完全二叉樹。
對一個給定的初始序列,怎樣把它建成一個堆呢?
1. 建立初始堆。
2. 從最後,從下向上逐個進行調整
*/
const int maxn = 100000;
int heap[maxn], n;
//向下調整
void downAjust(int low, int high)
{
int i=low, j=i*2;
while(j<=high)//存在孩子結點
{
if(j+1<=high && heap[j+1]> heap[j])//右邊大
j = j + 1;//讓j存儲右孩子下標
//如果孩子中最大的權值比欲調整結點i大
if(heap[j] > heap[i])
{
swap(heap[j], heap[i]);//交換最大權值的孩子與欲調整結點i
i = j;//保持i爲欲調整結點,j爲i的左孩子
j = i * 2;
}
else
break;//孩子的權值均比欲調整結點i小,調整結束
}
}
//建堆 O(n)
void createHeap()
{
for(int i=n/2; i>=1; i--)
downAjust(i,n);
}
void heapSort()
{
createHeap();//建堆
for(int i=n; i>1; i--)//倒着枚舉,直到堆中只有一個元素
{
swap(heap[i], heap[1]);
downAjust(1, i-1);//調整堆頂
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1; i<=n; i++)
scanf("%d",&heap[i]);
heapSort();
for(int i=1; i<=n; i++)
{
printf("%d", heap[i]);
if(i!=n)
printf(" ");
else
printf("\n");
}
}
return 0;
}