题目
思路:
乙级的题目不会直接考数据结构,对于几种排序算法也不会直接让你求。
本题考的插入和归并排序,其实不用完全掌握并写出代码也能做(能掌握当然好了)。只要理解了插入排序和归并排序的思路即可。 不行,还是得会,不然求不了归并的下一轮。
插入排序:将数组的第一个数认为是有序数组,把数组中其余n-1个数,插入到有序数组中,直至数组中的所有数有序排列为止。
对本题而言,插入排序过程中的前某m项是有序的。(从题目来看是从后往前扫描)
代码实现从小到大排序:
#include<stdio.h>
void InsertionSort(int *num,int n)
{
int i = 0;
int j = 0;
int tmp = 0;
for(i = 1;i<n;i++)//n个数要进行n-1趟
{
tmp = num[i];//从待插入组取出第一个元素。
j = i-1; //i-1即为有序组最后一个元素(与待插入元素相邻)的下标 ,开始时j=i-1=0。
while(j>=0&&tmp<num[j]) //注意判断条件为两个,j>=0对其进行边界限制。第二个为插入判断条件
{
num[j+1] = num[j];//若不是合适位置,有序组元素向后移动
j--;
}
num[j+1] = tmp;//找到合适位置,将元素插入。
}
}
int main()
{
int i = 0;
int num[8]={9,3,4,2,6,7,5,1};
InsertionSort(num,8);
for(i=0;i<8;i++)
{
printf("%d ",num[i]);
}
return 0;
}
归并排序:
归并排序有两种思路
1. 自顶向下(Top-Down)
直接在原序列上直接归并排序,每次归并排序分别对左右两边进行归并排序,直至细分到两两分组。
2.自底向上(Bottom-Up)
假设序列共有 n 个元素:
1. 先相邻两两分组进行归并排序
2. 再相邻四四分组进行归并排序
3. 再相邻八八分组进行归并排序
4. 重复扩大分组规模,直到所有元素排序完毕
5. …
对本题而言,显然采用的是第二种,自底向上,先两两分组排序。
代码出处:https://blog.csdn.net/Silence_R/article/details/86524975
#include<stdio.h>
/*归并排序*/
void Merge_Sort(int *arr, int *temparr,int start,int mid,int end)
{
int left_start = start ;
int left_end = mid ;
int right_start = mid+1 ;
int right_end = end ;
int index = start ;
while(left_start<=left_end&&right_start<=right_end)
{
if(arr[left_start]>arr[right_start])
temparr[index++] = arr[right_start++] ;
else
temparr[index++] = arr[left_start++] ;
}
while(left_start<=left_end)
temparr[index++] = arr[left_start++] ;
while(right_start<=right_end)
temparr[index++] = arr[right_start++] ;
for(index = start ;index<=end ;++index)
arr[index] = temparr[index] ;
}
void Sort_Message(int *arr, int *temparr,int start,int end)
{
if(start<end)
{
int mid = (start+end)/2 ;
Sort_Message(arr,temparr,start,mid) ;
Sort_Message(arr,temparr,mid+1,end) ;
Merge_Sort(arr,temparr,start,mid,end) ;
}
}
int main(void)
{
int a[] = {9,2,5,3,7,4,8,0} ;
int n = sizeof(a)/sizeof(a[0]) ;
int i, temp[8] ;
printf("原序列为:") ;
for(i=0;i<n;++i)
printf("%d ",a[i]) ;
printf("\n") ;
Sort_Message(a,temp,0,n-1) ;
printf("\n排后序列:") ;
for(i=0;i<n;++i)
printf("%d ",a[i]) ;
printf("\n") ;
return 0 ;
}
理解了两种排序方式后,本题的要求其实就很明显了:
给出原数组,判断前n个数是否有序——插入排序;else——归并排序。
或者:
判断是否所以数组两两有序或四四有序——归并排序;else——插入排序。
再进行求排序的下一轮:
对于插入排序,直接sort到有序位的下一位。
对于归并排序,求一遍归并排序。
AC代码
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
int n, a[100], b[100], i, j;
cin >> n;
for(int i = 0; i < n; i++)//原数组
cin >> a[i];
for(int i = 0; i < n; i++)//排序数组
cin >> b[i];
for(i = 0; i < n - 1 && b[i] <= b[i + 1]; i++);//判断插入排序:前i个有序,当发现无序时跳出循环
for(j = i + 1; a[j] == b[j] && j < n; j++);
if(j == n){ //上面循环遍历后,如果j==n,说明前 i个有序,后i+1到n-1个未排序。很明显为插入排序。
cout << "Insertion Sort" << endl;
sort(a, a + i + 2); //插入排序再迭代一轮,就是将第i+1个也排序进去。 a[i+1]在sort函数中地址是a+i+2
}
else{ //反之则为归并排序
cout << "Merge Sort" << endl; //输出再排序一轮的数组
int k = 1, flag = 1; //
while(flag){
flag = 0;
for(int i = 0; i < n; i++){ //对数组a遍历,只要有和b数组不一样的就继续。
if(a[i] != b[i]) //如果两数组一样,说明到了题目给出的那轮。跳出循环。
flag = 1;
}
k = k * 2; //k = 2 4 8...n。从两两一组开始,每组排序。
for(int i = 0; i < n / k; i++) //划分 n / k个组,对每个组内进行排序。
sort(a + i * k, a + (i + 1) * k);
sort(a + n / k * k, a + n); //对序列最后不足一组的元素排序。
}
}
for(j = 0; j < n; j++){
if(j != 0) printf(" ");
printf("%d", a[j]);
}
return 0;
}