插入排序还是堆排序(第十二周编程题)
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;
}
}
}
}