PAT_甲級_1098 Insertion or Heap Sort

題目大意:

給定一個待排序序列和排序若干次的序列,要求判斷是獲得目標序列是經過插入排序仍是堆排序,而後在輸出再排序一次後的序列便可。算法

算法思路:

這裏考察的就是插入排序和堆排序的完整排序的過程,循序漸進的來就好。函數

插入排序:

首先將序列劃分爲有序序列部分和無序序列部分,初始有序序列爲序列中第一個元素,對於長度爲N的序列,插入排序會通過N-1趟排序,完成將N-1個無序序列的元素依次插入到有序序列之中,那麼能夠看到,插入排序分爲外部循環控制趟數,內部循環負責找到插入位置,每次循環使用t暫存待插入元素,而後在$[1,j]$(有序序列)中查詢待插入位置loc,只要$t>=temp[j]$,說明找到插入位置$j+1$,退出內層循環,將$j+1$位置的元素賦值爲t便可。spa

堆排序:

因爲目標序列是遞增系列,那麼咱們須要創建大根堆,咱們初始序列做爲大根堆的層序遍歷序列,而後從最後一個非葉子節點到根節點,依次向下調整,只要孩子節點中有比當期父節點大的,就交換孩子節點和父節點,而且向下依次遞推查詢,直到孩子節點的權重均比父節點小中止調整。這樣就完成了初始大根堆的創建過程。堆排序就是將根節點和最後一個節點(未排序節點)進行交換,而後再向下調整根節點。這樣就完成了一次堆排序的過程,每一次堆排序都會固定一個最大的元素在最後。code

因爲題目要求判斷已排序部分的序列是插入排序仍是堆排序的結果之上再進行一次排序,那麼咱們使用$same$標誌已排序的部分序列是不是由當前的排序算法獲得的,若是在排序完成後,判斷$same$爲$true$,那麼就說明能夠退出排序過程,進行相應的輸出。若是$same$爲$false$,那麼就使用$isSame$函數更新$same$的值。blog

注意點:

  • 一、堆排序的根節點下標爲1.
  • 二、插入排序的初始插入位置默認爲1,是爲了處理像3 1這種特殊狀況。
  • 三、初始序列不參與和部分有序序列的比較,必定得先排序一次之後再比較是否相同。
  • 四、這裏題目要求是目標朝着遞增序列的方向排序,也便是最後的結果是從小到大,這裏得注意堆排序是大根堆排序後纔是遞增序列,小根堆排序後是遞減序列,由於每次都是從根節點和最後一個結點交換,最大(大根堆)或者最小(小根堆)的結點都在後面.

提交結果:

image.png

AC代碼:

#include <cstdio>
#include <algorithm>

using namespace std;

int N;// 節點個數
int init[105];//初始序列
int temp[105];//暫存初始序列
int partial_sorted[105];//部分排序序列

bool isSame(){
    for (int i = 1; i <= N; ++i) {
        if(temp[i]!=partial_sorted[i]){
            return false;
        }
    }
    return true;
}

bool InsertionSort(){
    bool same = false;
    // N-1輪排序
    for (int i = 1; i < N; ++i) {
        int t = temp[i+1];//暫存待插入元素
        int loc = 1;// 待插入位置,初始爲1,考慮3 1的特殊狀況
        for (int j = i; j >= 1; --j) {
            if(t<temp[j]){
                temp[j+1] = temp[j];
            } else {
                // 找到插入位置
                loc = j+1;
                break;
            }
        }
        temp[loc] = t;
        if(same){
            // 在相等的狀況下,又排序了一次
            break;
        }
        if(isSame()) same = true;//已經相同了,再排序一次
    }
    return same;
}

// 調整[low,high]的節點權重,low從最後一個非葉節點開始一直到1,high爲當前堆須要調整的最後一個元素
void downAdjust(int low,int high){
    int i = low;
    int j = 2*i;//i的左孩子
    while (j<=high){
        // 只要左孩子一直存在,就向下調整
        if(j+1<=high&&temp[j+1]>temp[j]){
            // 右孩子節點更小
            j = j+1;
        }
        if(temp[j]>temp[i]){
            // 孩子節點的值更小
            swap(temp[j],temp[i]);
            i = j;
            j = 2*i;
        }else {
            // 孩子權重更加小,就中止比較
            break;
        }
    }
}

void createHeap(){
    for(int i=N/2;i>=1;--i){
        downAdjust(i,N);
    }
}

void print(){
    for(int i=1;i<=N;++i){
        printf("%d",temp[i]);
        if(i<N) printf(" ");
    }
}

void HeapSort(){
    createHeap();//先建堆
    // 將最後的節點和堆頂的節點交換,而後調整
    bool same = false;
    for(int i=N;i>=2;--i){
        swap(temp[i],temp[1]);
        downAdjust(1,i-1);
        if(same){
            printf("Heap Sort\n");
            print();
            break;
        }
        if(isSame()){
            same = true;
        }
    }
}

int main()
{
    scanf("%d",&N);
    for (int i = 1; i <= N; ++i) {
        scanf("%d",&init[i]);
        temp[i] = init[i];
    }
    for (int i = 1; i <= N; ++i) {
        scanf("%d",&partial_sorted[i]);
    }
    if(InsertionSort()){
        printf("Insertion Sort\n");
        print();
    } else {
        // 重置temp
        for (int i = 1; i <= N; ++i) {
            temp[i] = init[i];
        }
        HeapSort();
    }
    return 0;
}
相關文章
相關標籤/搜索