【算法】归并排序:自底向上、自顶向下(分治思想)的实现
1 自底向上
-
算法
import java.util.Arrays; /** * 归并排序:自底向上 */ public class Sort { /** * @title: mergeSort * @description: 归并排序 主算法:将两个(或以上)的有序序列组成新的有序序列 * 把一个长度为n的无序序列看作是n个长度为1的有序序列,并做两两合并,得到n/2个长度为2的子序列, * 如此重复,每次n*2,直到得到一个长度为n的有序序列; * @date: 2021/3/8 * @param value */ public static void mergeSort(int[] value) { int[] valueSorted = new int[value.length]; int n = 1;// 初值为1,单个子表的元素数量 /** * 注意!最后一次一趟归并,必然是把valueSorted中的子序列归并到value中 * 原因:局部变量valueSorted,在函数mergeSort(int[] value) 调用完毕后会销毁, 所以要把结果放到传递过来的形参value中 */ while (n < value.length) {// 每次循环,子序列长度n加倍 mergeAll(value, valueSorted, n);// 一趟归并,将value中若干子序列归并到valueSorted n = 2 * n; if (n >= value.length) { //value = valueSorted; 这样赋值无效 System.arraycopy(valueSorted, 0, value, 0, value.length); } if (n < value.length) { mergeAll(valueSorted, value, n);// 一趟归并,将valueSorted中若干子序列归并到value n = 2 * n; } } } /** * @title: mergeAll * @description: 归并排序 中的一趟归并 * @date: 2021/3/8 * @param value 预备归并的序列 * @param valueSorted 得到的归并结果序列 * @param n 归并的元素长度 */ public static void mergeAll(int[] value, int[] valueSorted, int n) { for (int i = 0; i < value.length; i += 2 * n) { merge(value, valueSorted, i, i + n, n); } } /** * @title: merge * @description: 归并排序 中的一次归并 * @date: 2021/3/8 * @param value 预备归并的序列 * @param valueSorted 得到的归并结果序列 * @param begin1 第一块开始位置 * @param begin2 第二块开始位置 * @param n 归并的元素长度 */ public static void merge(int[] value, int[] valueSorted, int begin1, int begin2, int n) { /** * i控制从value的begin1开始遍历, j控制从value的beigin2开始遍历, k控制valueSorted遍历增加元素 */ int i = begin1, j = begin2, k = begin1; while (i < begin1 + n && j < begin2 + n && j < value.length) { // i肯定小于j,所以只需判断j<value.length的边界情况 if (value[i] < value[j])// 升序 valueSorted[k++] = value[i++]; else valueSorted[k++] = value[j++]; } while (i < begin1 + n && i < value.length) {// j遍历完,将i剩下元素放入valueSorted valueSorted[k++] = value[i++]; } while (j < begin2 + n && j < value.length) {// i遍历完,将j剩下元素放入valueSorted valueSorted[k++] = value[j++]; } } public static void main(String[] args) { Sort sort = new Sort(); int[] a = {8, 100, 10, 1, 9, 5, 2, 99}; System.out.println("原数组:" + Arrays.toString(a)); sort.MergeSort(a); System.out.println("排序后的数组:" + Arrays.toString(a)); } }
2 自顶向下
-
分治思想:将一个大问题化为规模小的问题,但解决方法相同;解决了最深层的n个问题后,一层层合并上去,最终解决大问题。
-
使用分治思想
import java.util.Arrays; /** * @author musecho801 * @title 归并排序(升序):自顶向下 * @description 分治思想。 * 将整体一分为二,对左半部分数组、右半部分数组分别进行递归,再合并 * @date 2021/3/10 16:57 */ public class Sort { /** * @title MergeSort * @description 归并排序入口 * @date 2021/3/10 17:30 * @Param value: 待排序数组 * @return: void */ public void MergeSort(int[] value) { mergeRecursion(value, 0, value.length - 1); } /** * @title mergeRecursion * @description 归并排序 递归:将整体一分为二,对左半部分数组、右半部分数组分别进行递归,再调用合并函数 * @date 2021/3/10 17:31 * @Param value: 待排序数组 * @Param low: 左半部分数组的开始下标 * @Param high: 右半部分数组的开始下标 * @return: void */ public void mergeRecursion(int[] value, int low, int high) { if (low >= high) return; int mid = (low + high) / 2; mergeRecursion(value, low, mid); mergeRecursion(value, mid + 1, high); merge(value, low, mid, mid + 1, high); } /** * @title merge * @description 合并被一分为二的数组,将两者排序 * @date 2021/3/10 17:31 * @Param value: 待排序数组 * @Param begin1: 左半部分数组的开始下标 * @Param end1: 左半部分数组的结束下标 * @Param begin2: 右半部分数组的开始下标 * @Param end2: 右半部分数组的结束下标 * @return: void */ public void merge(int[] value, int begin1, int end1, int begin2, int end2) { int i = begin1, j = begin2, k = 0; //注意:定义的数组长度 int[] valueSorted = new int[end2 - begin1 + 1];//临时结果数组 //两个都没结束 while (i <= end1 && j <= end2) { if (value[i] <= value[j]) valueSorted[k++] = value[i++]; else valueSorted[k++] = value[j++]; } //前者没完 while (i <= end1) { valueSorted[k++] = value[i++]; } //后者没完 while (j <= end2) { valueSorted[k++] = value[j++]; } //只更新发生变动的排序位置元素 i = begin1; for (int u = 0; u < end2 - begin1 + 1; u++) { value[i++] = valueSorted[u]; } } public static void main(String[] args) { Sort sort = new Sort(); int[] a = {8, 100, 10, 1, 9, 5, 2, 99}; System.out.println("原数组:" + Arrays.toString(a)); sort.MergeSort(a); System.out.println("排序后的数组:" + Arrays.toString(a)); } }