插入排序还是堆排序(第十二周编程题)

7-3 插入排序还是堆排序 (25 分)
根据维基百科的定义:

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

堆排序也是将输入分为有序和无序两部分,迭代地从无序部分找出最大元素放入有序部分。它利用了大根堆的堆顶元素最大这一特征,使得在当前无序区中选取最大元素变得简单。

现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?

输入格式:
输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。

输出格式:
首先在第 1 行中输出Insertion Sort表示插入排序、或Heap Sort表示堆排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。

输入样例 1:
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
输出样例 1:
Insertion Sort
1 2 3 5 7 8 9 4 6 0
输入样例 2:
10
3 1 2 8 7 5 9 4 6 0
6 4 5 1 0 3 2 7 8 9
输出样例 2:
Heap Sort
5 4 3 1 0 2 6 7 8 9

我的想法:

这道题目很容易读懂,就是两个排序——插入排序和堆排序,给出中间两个序列,判断排序方式,然后输出下一个序列,没别的内容了。其实完全可以按部就班的建堆,一点一点插入,然后一步一步排列,排列一次判断一次,直到找到样例,然后输出下一次。找不到就是插入排序,再根据插入排序算法计算到样例那一步,然后输出下一步。(傻瓜做法,但傻人有傻福,完全可以AC)【我不知道我没试过会不会超时】

仔细观察其实会发现,有好多空子可以钻:
1。堆排序的样例,中间任何一步中的第一个元素肯定大于第二个,而相应的插入排序的第一个元素肯定会小于第二个元素,所以可以根据这个判断排序方式。
2。堆排序根本不需要写建堆的插入函数,Shiftup也不需要,因为中间的任何一步的前面肯定是一个堆,而后面的内容从大到小往回排列已经排好了。

我卡在了某处

我一开始判断插入排序排到的位置的时候,有一个点出现了段错误(还好是特么段错误,要是答案错误我会开始怀疑堆排序的代码有问题,做完根本没的睡了就)。
先给你看一下我这部分代码:

int needsort=0;
		for (int i = N; i >= 1; i--) {
			if (a[i] != sample[i]) {
				needsort = i + 1; break;
			}
		}

我是判断的第二行和第一行是不是一致,如果一致说明还没动(还没排到这里)。然而段错误?因为一开始needsort我没有赋值。
是这样的样例没有考虑:
8
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8
这样的样例一定要考虑,以为有一个点是这样的。它肯定是插入排序,因为堆排序的中间步骤的堆顶不可能是1。而插入排序对于有序数列是从头到尾都不改变的——这和题目中的答案唯一并不冲突,因为每一步的结果都是唯一的答案——1 2 3 4 5 6 7 8.
所以将判断位置的函数改成这样:

int needsort = 0, temp; bool next = false;
		for (int i = 2; i <= N; i++) {
			for (int j = i; j > 1; j--) {
				if (a[j] < a[j - 1]) {
					temp = a[j];
					a[j] = a[j - 1];
					a[j - 1] = temp;
				}
				else break;
			}

就,按部就班写了两层循环,O(n^2)的时间复杂度,完全按照插入排序方式来寻找位置。

AC代码:

#include<iostream>
using namespace std;
int a[105] = { -1 };
int sample[105] = { -1 };
int main() {
	int N; cin >> N;
	for (int i = 1; i <= N; i++)cin >> a[i];
	for (int i = 1; i <= N; i++)cin >> sample[i];
	if (sample[1] > sample[2]) {//HeapSort
		int stepnumber = 0;
		for (int i = 3; i <= N; i++) {
			if (sample[1] < sample[i]) {
				stepnumber = i; break;
			}
		}
		int temp = sample[1];
		sample[1] = sample[stepnumber - 1];
		sample[stepnumber - 1] = temp;
		stepnumber -= 2;
		int n = 1, max;
		for (; n * 2 <= stepnumber;) {
			if (n * 2 == stepnumber)max = stepnumber;
			else
				max = sample[n * 2] < sample[n * 2 + 1] ? n * 2 + 1 : n * 2;
			if (sample[n] < sample[max]) {
				temp = sample[max];
				sample[max] = sample[n];
				sample[n] = temp;
				n = max;
			}
			else break;
		}
		cout << "Heap Sort" << endl << sample[1];
		for (int i = 2; i <= N; i++)cout << " " << sample[i];
	}
	else {//插入排序
		int needsort = 0, temp; bool next = false;
		for (int i = 2; i <= N; i++) {
			for (int j = i; j > 1; j--) {
				if (a[j] < a[j - 1]) {
					temp = a[j];
					a[j] = a[j - 1];
					a[j - 1] = temp;
				}
				else break;
			}
			if (next) {
				cout << "Insertion Sort" << endl << a[1];
				for (int i = 2; i <= N; i++)cout << " " << a[i]; system("pause");
				return 0;
			}
			for (int i = 1; i <= N; i++) {
				if (sample[i] != a[i]) {
					next = false; break;
				}
				next = true;
			}
		}
	}
}
posted @ 2019-11-15 20:31  爱和九九  阅读(150)  评论(0编辑  收藏  举报