归并排序

    科技2022-07-11  117

    #include <stdio.h> #include <stdlib.h> void Merge (int arr[], int L, int M, int R) { /*此处数组的头指针和尾指针需要参数给出,便于获取数组长度*/ int LEFT_SIZE = M - L + 1; //M算作左序列一份子,左序列长度额外加一 int RIGHT_SIZE = R - M; //M不算右序列份子,右序列长度不需要加一 //分别新建数组存放左、右子序列 int L_arr[LEFT_SIZE]; int R_arr[RIGHT_SIZE]; //先原封不动将数组左、右两边分别copy到左、右子序列 for (int i = L; i <= M; i++) { //M是属于左序列的,所以要从L到M遍历 L_arr[i-L] = arr[i]; } for (int j = M+1; j <= R; j++) { //M不属于右序列,所以从(M+1)遍历到R R_arr[j-M-1] = arr[j]; } //复制完毕后,同时操作左右子序列,排序、重构母序列 int i = 0; //左序列起始位置 int j = 0; //右序列起始位置 int k = L; //k作为母序列控制指针 //i,j都未到终点时,交替移动 //此处不等号不取等,就是因为数组长度与末位下标相差1 while (i < LEFT_SIZE && j < RIGHT_SIZE) { if (L_arr[i] <= R_arr[j]) { arr[k] = L_arr[i]; i++; k++; } else { arr[k] = R_arr[j]; j++; k++; } } //若j先超过终点,将左边子序列后面剩余的数按顺序照搬到母序列 while (i < LEFT_SIZE) { arr[k] = L_arr[i]; k++; i++; } //若i先超过终点,将右边子序列后面剩余的数按顺序照搬到母序列 while (j < RIGHT_SIZE) { arr[k] = R_arr[j]; k++; j++; } } void MergeSort (int arr[], int L, int R) { /* 为什么将分界点的计算放到MergeSort()里面而非其他位置? 1.Merge()是被MergeSort()调用的子函数,在MergeSort中算出M,以参数形式传给Merge(),更方便 2.避免了在main()中计算M的麻烦,保证了main()中只写主干程序 */ /* 此处有巨坑,算出半长度后要记得加上左指针值, 另外要考虑整数除法其实是向下取整的, 要特别注意到最深处(每个子序列只有一个数)时,L,M,R的取值分别是多少, 以此确定[防止递归死循环的判定条件]应该怎么写, 可以举简单序列在纸上模拟运行到最后一步,观察L,M,R的特点, 本例中得出判定条件为 if (L > (R-1)) */ int M = L + (R - L) / 2; //中点到底偏向哪边不重要,举简单例子观察就行 //递归调用函数必备,防死循环的条件判定 //一般来讲,最好通过观察实际用例来写,yy很容易出错 if (L > (R-1)) { return; } else { MergeSort(arr, L, M); MergeSort(arr, M+1, R); Merge(arr, L, M, R); } } int main () { //输入待排序列的长度与内容 int n = 0; int arr[100000]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d",&arr[i]); } //排序 MergeSort(arr, 0, n-1); //输出结果 for (int i = 0; i < n; i++) { printf("%d ",arr[i]); } return 0; } /* 补充: 1.测试用例一定要全面,长度为奇数和偶数的序列都要测试; 2.从0开始还是从1开始?在写的时候就要想好,等全部码完再查错很困难; 3.不等号到底要不要取等?用特殊样例测清楚再写; 4.如果从0开始管理数组,特别注意数组长度和末尾下标之间是相差1的; */

     

    Processed: 0.040, SQL: 8