P 1035 插入与归并

转跳点 :🐏

 

1035 插入与归并 (25分)
 

根据维基百科的定义:

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

归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。

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

输入格式:

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

输出格式:

首先在第 1 行中输出Insertion Sort表示插入排序、或Merge 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 0 6
1 3 2 8 5 7 4 9 0 6
 

输出样例 2:

Merge Sort
1 2 3 8 4 5 7 9 0 6

  这道题比较有意思,需要用到归并排序和插入排序的知识,两种排序的博客我都写了,自行转跳。

这道题有两种解法,

    第一种是写两个排序算法,每执行完一轮就比较一次,时间复杂度 T(O) = O(N^3+N^2logN),太暴力了

    第二种是利用插入排序的特性:插入排序,前面是排好序的,后面是与初始序列相同。只要符合这个条件的就是插入,不符合就是归并

用第一种方法暴力就行,但是第二种就需要对归并和插入排序十分熟悉,因为要写一个单步的归并和插入。插入的单步十分容易实现只要知道第几个没排好,继承索引,找到位置插入就行了。而归并就有些麻烦,需要完完整整的归并。

 

AC代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 int Merge = 0;
  6 void InsertSorted(int arr[], int mid[], int n);
  7 void MergeSorted(int arr[], int mid[], int n);
  8 int ArrayEqual(int arr[], int ary[], int n);
  9 void ArrayPrint(int arr[], int n);
 10 
 11 int main(void)
 12 {
 13     static int n;
 14     int arr[101];
 15     int ary[101];
 16     int mid[101];
 17 
 18     scanf("%d", &n);
 19 
 20     for (int i = 0; i < n; i++)
 21     {
 22         scanf("%d", &arr[i]);
 23         ary[i] = arr[i];
 24     }
 25 
 26     for (int i = 0; i < n; i++)
 27     {
 28         scanf("%d", &mid[i]);
 29     }
 30     
 31     InsertSorted(arr, mid, n);
 32     if (Merge)
 33     {
 34         MergeSorted(ary, mid, n);
 35     }
 36 
 37     return 0;
 38 }
 39 
 40 //插入排序
 41 void InsertSorted(int arr[], int mid[], int n)
 42 {
 43     int j, temp;
 44 
 45     for (int i = 1; i < n; i++)
 46     {
 47         j = i;
 48         temp = arr[i];
 49         while (j > 0 && temp < arr[j - 1])
 50         {
 51             arr[j] = arr[j - 1];
 52             j--;
 53         }
 54         arr[j] = temp;
 55 
 56         if (ArrayEqual(arr, mid, n))
 57         {
 58             j = ++i;
 59             temp = arr[i];
 60             while (j > 0 && temp < arr[j - 1])
 61             {
 62                 arr[j] = arr[j - 1];
 63                 j--;
 64             }
 65             arr[j] = temp;
 66             printf("Insertion Sort\n");
 67             ArrayPrint(arr, n);
 68             Merge = 0;
 69             return;
 70         }
 71     }
 72     Merge = 1;
 73 }
 74 
 75 void MergeAdd(int arr[], int left, int mid, int right, int *tmp)
 76 {
 77     int i = left;
 78     int j = mid + 1;
 79     int k = left;
 80     while (i <= mid && j <= right)
 81     {
 82         tmp[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
 83     }
 84     while (i <= mid)
 85     {
 86         tmp[k++] = arr[i++];
 87     }
 88     while (j <= right)
 89     {
 90         tmp[k++] = arr[j++];
 91     }
 92     //把tmp中的内容拷给arr数组中
 93     //进行归并的时候,处理的区间是arr[left,right),对应的会把
 94     //这部分区间的数组填到tmp[left,right)区间上
 95     memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
 96 }
 97 
 98 void MergeSort(int arr[], int len, int *tmp, int mid[], int n)
 99 {
100     if (len <= 1)
101     {
102         return;
103     }
104     int flag = 0;
105 
106     //定义一个步长gap,初始值为1,相当于每次只合并两个长度为1的元素
107     for (int gap = 1; gap <= len; gap *= 2)
108     {
109         for (int i = 0; i <= len; i += 2 * gap)
110         {
111             int beg = i;
112             int mid = (gap - 1) + i;
113             if (mid >= len)
114             {
115                 mid = len;
116             }
117             int end = mid + gap;
118             if (end >= len)
119             {
120                 end = len;
121             }
122             MergeAdd(arr, beg, mid, end, tmp);
123         }
124         if (flag)
125         {
126             printf("Merge Sort\n");
127             ArrayPrint(arr, n);
128             return;
129         }
130         if (ArrayEqual(arr, mid, n))
131         {
132             flag = 1;
133         }
134     }
135 }
136 //归并排序接口
137 void MergeSorted(int arr[], int mid[], int n)
138 {
139     int *temp = malloc(sizeof(int) * n);
140     MergeSort(arr, n - 1, temp, mid, n);
141     free(temp);
142 }
143 //输出数组
144 void ArrayPrint(int arr[], int n)
145 {
146     for (int i = 0; i < n; i++)
147     {
148         printf("%d%s", arr[i], n - 1 == i ? "" : " ");
149     }
150 }
151 //判断相等
152 int ArrayEqual(int arr[], int ary[], int n)
153 {
154     for (int i = 0; i < n; i++)
155     {
156         if (arr[i] != ary[i])
157         {
158             return 0;
159         }
160     }
161     return 1;
162 }

 

第二种:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int isinsertion(int n, int num[], int mid[]);
 5 int nextmerge(int n, int num[], int mid[]);
 6 int cmp(const void *a, const void *b) { return (*(int *)a) > (*(int *)b); }
 7 
 8 int main()
 9 {
10     int n, num[100], mid[100];
11     int i;
12     scanf("%d", &n);
13     for (i = 0; i < n; i++)
14     {
15         scanf("%d", &num[i]);
16     }
17     for (i = 0; i < n; i++)
18     {
19         scanf("%d", &mid[i]);
20     }
21 
22     if (isinsertion(n, num, mid))
23     {
24         nextmerge(n, num, mid);
25     }
26 
27     for (i = 0; i < n; i++)
28     {
29         printf("%d%s", num[i], i == n - 1 ? "" : " ");
30     }
31     return 0;
32 }
33 
34 int isinsertion(int n, int num[], int mid[])
35 {
36     int i, lenth;
37     for (i = 0; i < n - 1 && mid[i] <= mid[i + 1]; i++)
38     {//前面是排好序的
39         continue;
40     }
41     for (i++, lenth = i; i < n && mid[i] == num[i]; i++)
42     {//后面是与初始序列相同
43         continue;
44     }
45     if (i < n)
46     {
47         return 1;
48     }
49     printf("Insertion Sort\n");
50     lenth++;
51     qsort(num, lenth, sizeof(int), cmp);
52     return 0;
53 }
54 
55 int nextmerge(int n, int num[], int mid[])
56 {
57     int i, j, lenth;
58     printf("Merge Sort\n");
59     for (lenth = 1, i = 0; i < n && lenth <= n; lenth *= 2)
60     { //只能一步步归并
61         for (i = 0; i < n && num[i] == mid[i]; i++)
62             ;
63         for (j = 0; j < n / lenth; j++)
64         {
65             qsort(num + j * lenth, lenth, sizeof(int), cmp);
66         }
67         qsort(num + j * lenth, n % lenth, sizeof(int), cmp);
68     }
69     return 0;
70 }

  偷懒了,用qsort”实现“归并

 

   PTA不易,诸君共勉!

posted @ 2020-01-21 14:57  秦_殇  阅读(257)  评论(0编辑  收藏  举报