数据结构(陈越)PAT练习题 第七周:排序(上)

来源:互联网 发布:华为网络电话机 编辑:程序博客网 时间:2024/05/29 19:14

07-1. 排序

时间限制
5000 ms
内存限制
128000 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue

给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。

本题旨在测试各种不同的排序算法在各种数据情况下的表现。各组测试数据特点如下:

  • 数据0:只有1个元素;
  • 数据1:11个不相同的整数,测试基本正确性;
  • 数据2:103个随机整数;
  • 数据3:104个随机整数;
  • 数据4:105个随机整数;
  • 数据5:105个顺序整数;
  • 数据6:105个逆序整数;
  • 数据7:105个基本有序的整数;
  • 数据8:105个随机正整数,每个数字不超过1000。

输入格式:

输入第一行给出正整数N(<= 105),随后一行给出N个(长整型范围内的)整数,其间以空格分隔。

输出格式:

在一行中输出从小到大排序后的结果,数字间以1个空格分隔,行末不得有多余空格。

输入样例:
114 981 10 -17 0 -20 29 50 8 43 -5
输出样例:
-20 -17 -5 0 4 8 10 29 43 50 981

这一题重点不在于全部通过,而是测试各种排序算法的性能比较。这里我按照课件里讲到的方法都进行了测试,先来看一下结果吧:



从结果来看,冒泡排序和选择排序的表现是最差的,有三个测试点都超时。其次是插入排序,有一个点超时。相比较而言,其它的排序算法效果要好很多。在希尔排序,我使用的是原始序列;堆排序中用的是最大堆,和希尔排序比起来,速度相差不大,不过内存占用更小些;递归的和非递归的归并排序相比较,非递归速度更快些,看来系统堆栈的调用挺耗时啊;库sort是STL中的排序算法,它使用的是快速排序算法,对于较小的数据则使用插入排序;库stable_sort是STL的另一种算法,和sort相比,它是一种稳定排序算法,其基本原理是归并排序,可以看到它明显要占用更多内存空间。在这里我使用的是cin和cout进行输入和输出,如果改用scanf和printf,应该会节省更多时间。下面是代码:

#include <iostream>#include <algorithm>using namespace std;// --冒泡排序--void bubble_sort( long a[], int N ){for (int j=N-1; j>0; --j){bool noChange = true;for (int i=0; i<j; ++i){if (a[i]>a[i+1]){swap( a[i], a[i+1] );noChange = false;}}if (noChange)break;}}// --插入排序--void insertion_sort( long a[], int N ){long tmp;int  i;for (int j=1; j<N; ++j){tmp = a[j];for (i=j; i>0 && a[i-1]>tmp; --i)a[i] = a[i-1];a[i] = tmp;}}// --希尔排序--void shell_sort( long a[], int N ){long tmp;int  i;for (int d=N/2; d>0; d/=2){for (int j=d; j<N; ++j){tmp = a[j];for (i=j; i>=d && a[i-d]>tmp; i-=d)a[i] = a[i-d];a[i] = tmp;}}}// --选择排序--void selection_sort( long a[], int N ){for (int i=0; i<N-1; ++i){int index = i;for (int j=i+1; j<N; ++j){if (a[index]>a[j])index = j;}swap( a[index], a[i] );}}// --堆排序--void heap_sort( long a[], int N ){int parent, child;long tmp;for (int i=(N-2)/2; i>=0; --i){tmp = a[i];for (parent=i; parent*2+1<N; parent=child){child = 2*parent+1;if (child!=N-1 && a[child]<a[child+1])++child;if (tmp>a[child])break;elsea[parent] = a[child];}a[parent] = tmp;}for (int i=N-1; i>0; --i){swap( a[0], a[i] );tmp = a[0];for (parent=0; parent*2+1<i; parent=child){child = 2*parent+1;if (child!=i-1 && a[child]<a[child+1])++child;if (tmp>a[child])break;elsea[parent] = a[child];}a[parent] = tmp;}}// --归并排序(递归)--void msort( long a[], long b[], int L, int R ){if (L<R){int C = (L+R)/2;;msort( a, b, L, C );msort( a, b, C+1, R );//mergeint L1=L, L2=C+1, Lb=L;while (L1<=C && L2<=R){if (a[L1]<=a[L2])b[Lb++] = a[L1++];elseb[Lb++] = a[L2++];}while (L1<=C)b[Lb++] = a[L1++];while (L2<=R)b[Lb++] = a[L2++];for (int i=L; i<=R; ++i)a[i] = b[i];}}void merge_sort_recul( long a[], int N ){long* b = new long [N];msort( a, b, 0, N-1 );delete [] b;}// --归并排序(非递归)--void merge( long a[], long b[], int L, int C, int R ){int L1=L, L2=C+1, Lb=L;while (L1<=C && L2<=R){if (a[L1]<=a[L2])b[Lb++] = a[L1++];elseb[Lb++] = a[L2++];}while (L1<=C)b[Lb++] = a[L1++];while (L2<=R)b[Lb++] = a[L2++];}void merge_pass( long a[], long b[], int N, int len ){int i;for (i=0; i<=N-2*len; i+=2*len)merge( a, b, i, i+len-1, i+2*len-1 );if (i+len<N)merge( a, b, i, i+len-1, N-1 );elsefor (int j=i; j<N; ++j)b[j] = a[j];}void merge_sort_norecul( long a[], int N ){long* b = new long [N];int len = 1;while (len<N){merge_pass( a, b, N, len );len *= 2;merge_pass( b, a, N, len );len *= 2;}delete [] b;}int main(){/*****************************/// --输入--int N;long* a;cin >> N;a = new long [N];for (int i=0; i<N; ++i)cin >> a[i];/*****************************///bubble_sort( a, N );// 冒泡排序//insertion_sort( a, N );// 插入排序//shell_sort( a, N );// 希尔排序//selection_sort( a, N );// 选择排序//heap_sort( a, N );// 堆排序//merge_sort_recul( a, N );// 归并排序(递归)//merge_sort_norecul( a, N );// 归并排序(非递归)//sort( a, a+N );stable_sort( a, a+N );/**********************************/// --输出--cout << a[0];for (int i=1; i<N; ++i)cout << ' ' << a[i];delete [] a;return 0;}


07-2. Insert or Merge

时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue

According to Wikipedia:

Insertion sort iterates, consuming one input element each repetition, and growing a sorted output list. Each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there. It repeats until no input elements remain.

Merge sort works as follows: Divide the unsorted list into N sublists, each containing 1 element (a list of 1 element is considered sorted). Then repeatedly merge two adjacent sublists to produce new sorted sublists until there is only 1 sublist remaining.

Now given the initial sequence of integers, together with a sequence which is a result of several iterations of some sorting method, can you tell which sorting method we are using?

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<=100). Then in the next line, N integers are given as the initial sequence. The last line contains the partially sorted sequence of the N numbers. It is assumed that the target sequence is always ascending. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in the first line either "Insertion Sort" or "Merge Sort" to indicate the method used to obtain the partial result. Then run this method for one more iteration and output in the second line the resulting sequence. It is guaranteed that the answer is unique for each test case. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input 1:
103 1 2 8 7 5 9 4 6 01 2 3 7 8 5 9 4 6 0
Sample Output 1:
Insertion Sort1 2 3 5 7 8 9 4 6 0
Sample Input 2:
103 1 2 8 7 5 9 4 0 61 3 2 8 5 7 4 9 0 6
Sample Output 2:
Merge Sort1 2 3 8 4 5 7 9 0 6

这一题是要根据输入判断是插入排序还是归并排序。在插入排序中,前面的数据是排好序的,而后面的数据还是原始的顺序,没有动过。所以只要根据这一点,就可以判断是不是插入排序了。如果是插入排序排序的话,那么很简单,只要再插一次就可以了。如果是归并排序的话,就得先想办法确认出当前的归并长度是多少。这里面有坑。。可能有人觉得从左往右扫一遍,只要数据变小了,那么扫过的长度就是归并长度。如果这样想,那就图样图森破了,来看一个例子:

1 2 3 8 5 7 4 9 0 6

对于上面的序列,从左往右扫,长度应该是4,但实际上长度应该是2,前面4的长度只是一个巧合。所以归并长度是由最短的已排好的序列决定的。当然这个最短还得考虑最后一小段序列,假如是下面这种情况:

1 2 3 8 4 5 7 9 0 6

最短的有序序列长度是2,不过归并长度应该是4。这里我的解决办法很简单,从左往右扫,只要数字变小,就观察这一段的序列长度,如果比之前的短就更新它,否则不操作。这样当扫到完最后一个数时,不会改变之前的记录。来看代码吧!

#include <iostream>using namespace std;bool isMergeSort = false;int  N;int* a;int* b;int idx=0;void merge( int a[], int b[], int L, int C, int R ){int L1=L, L2=C+1, Lb=L;while (L1<=C && L2<=R){if (a[L1]<=a[L2])b[Lb++] = a[L1++];elseb[Lb++] = a[L2++];}while (L1<=C)b[Lb++] = a[L1++];while (L2<=R)b[Lb++] = a[L2++];}void merge_pass( int a[], int b[], int N, int len ){int i;for (i=0; i<=N-2*len; i+=2*len)merge( a, b, i, i+len-1, i+2*len-1 );if (i+len<N)merge( a, b, i, i+len-1, N-1 );elsefor (int j=i; j<N; ++j)b[j] = a[j];}int main(){cin >> N;a = new int [N];b = new int [N];for (int i=0; i<N; ++i)cin >> a[i];for (int i=0; i<N; ++i)cin >> b[i];//check array bwhile (b[idx]<=b[idx+1])++idx;for (int i=idx+1; i<N; ++i){if (a[i]!=b[i]){isMergeSort = true;break;}}//---------------------------if (!isMergeSort){cout << "Insertion Sort\n";int tmp = b[idx+1], i;for (i=idx+1; i>0&&b[i-1]>tmp; --i)b[i] = b[i-1];b[i] = tmp;cout << b[0];for (i=1; i<N; ++i)cout << ' ' << b[i];}else{cout << "Merge Sort\n";int len = idx+1, cur_len = 1;for (int i=idx+1; i<N-1; ++i){if (b[i+1]>=b[i])++cur_len;else{if (cur_len<len)len = cur_len;cur_len = 1;}}//----------------merge_pass( b, a, N, len );cout << a[0];for (int i=1; i<N; ++i)cout << ' ' << a[i];}delete [] a;delete [] b;return 0;}

0 0
原创粉丝点击