1. 程式人生 > 實用技巧 >[PAT] A1098 Insertion or Heap Sort

[PAT] A1098 Insertion or Heap Sort

(重要!堆!)

題目大意

給出n和n個數的序列a和b,a為原始序列,b為排序其中的一個步驟,問b是a經過了堆排序還是插入排序的,並且輸出它的下一步。

測試點2:插入排序時,要考慮輸入的兩個序列是相同的情況。即第一次判斷時原序列的第一個數和第二個數本身有序(題目保證了答案唯一,所以不會出現連續幾個本身都有序的情況)。一開始我寫錯了,是因為先判斷了序列是否相同再進入迴圈。

化簡

找到兩個排序中那個最容易分辨出來——明顯是插入排序。在判斷是否為插入排序時,無需模擬插入排序的過程。插入排序的特點是:b陣列前面的順序是從小到大的,後面的順序不一定,但是一定和原序列的後面的順序相同。所以只要遍歷一下前面幾位,遇到不是從小到大的時候,開始看b和a是不是對應位置的值相等,相等就說明是插入排序,否則就是堆排序。這樣也可避免上面說到的兩個輸入序列相同的情況。
插入排序的下一步就是把第一個不符合從小到大的順序的那個元素插入到前面已排序的裡面的合適的位置,那麼只要對前幾個已排序的+後面一位這個序列sort排序即可。找到第一個不滿足條件的下標p並且賦值給index。陣列下標從1開始,所以插入排序的下一步就是sort(b.begin() + 1, b.begin() + index + 1);

後的b陣列。
當確認是使用堆排序方法時,也不用模擬一遍堆排序過程了(即不用管序列a。序列a只是用於判斷a到b的過程用的是什麼方法。既然已經知道了方法,直接從b求下一步就行,也就是在b的基礎上繼續進行一次向下調整的步驟)。因為序列b的前幾項(即還沒排序的部分)一定已經是一個大頂堆,它的特點是最大值在第一個數b[1]。從後往前找到第一個沒排好序的數b[p],讓它與b[1]交換,再讓b[1...p-1]做一次downAdjust即可。

AC程式碼

精簡後的程式碼

原始程式碼

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <cstdio>
#include <vector>
#include<algorithm>
using namespace std;
#define N 102
vector<int>initial, part, heap, insert;
void downAdjust(int low, int high) {
	int i = low, j = i * 2 + 1;
	while (j <= high) {//如果存在孩子(孩子還沒越過邊界)
		if (j + 1 <= high && heap[j + 1] > heap[j])
			j = j + 1;
		if (heap[i] < heap[j]) {
			swap(heap[i], heap[j]);
			i = j;
			j = i * 2 + 1;
		}
		else break;//一旦孩子不比父子大,往下不用再比了。因為下面的都是已經排好了更小的。
	}
}
int main() { 
	int n, i, j;    
	scanf("%d", &n); 
	initial.resize(n);
	insert.resize(n);
	part.resize(n);
	heap.resize(n);
	for (i = 0;i < n;i++)scanf("%d", &initial[i]);
	for (i = 0;i < n;i++)scanf("%d", &part[i]);
	heap = initial;
	insert = initial;
	i = 1;
	while (i < n) {
//這裡一定不能先判斷insert和part是否相同。因為可能是經歷了幾次後結果還是和原來一樣(題目說了不可能是0次)。如果一開始就判斷的話,會直接不進入迴圈
		for (j = i;j > 0;j--) {
			if (insert[j] < insert[j - 1])
				swap(insert[j], insert[j - 1]);
		}
		i++;
		if (insert == part)break;
	}
	if (i < n) {
		printf("Insertion Sort\n");
		for (j = i;j > 0;j--) {
			if (insert[j] < insert[j - 1])
				swap(insert[j], insert[j - 1]);
		}
		printf("%d", insert[0]);
		for (j = 1;j < n;j++)
			printf(" %d", insert[j]);
	}
	else {
		printf("Heap Sort\n");
		for (i = (n - 1) / 2; i >= 0; i--) {
			downAdjust(i, n - 1);
		}
		i = n - 1;
		while (heap != part) {
			swap(heap[i], heap[0]);
			downAdjust(0, i - 1);
			i--;
		}
		swap(heap[i], heap[0]);
		downAdjust(0, i - 1);
		printf("%d", heap[0]);
		for (j = 1;j < n;j++)
			printf(" %d", heap[j]);
	}
	return 0; 
}