【算法筆記第9.7節-堆排序】問題 A: 算法10-10,10-11:堆排序

問題 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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章