一对一直播软件源码,归并排序的优化策略
一对一直播软件源码,归并排序的优化策略
归并排序遵循分治的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后合并这些子问题的解来建立原问题的解,归并排序的步骤如下:
1、划分:分解待排序的 n 个元素的序列成各具 n/2 个元素的两个子序列,将长数组的排序问题转换为短数组的排序问题,当待排序的序列长度为 1 时,递归划分结束
2、合并:合并两个已排序的子序列得出已排序的最终结果
归并排序的代码实现如下:
private void sort(int[] nums, int left, int right) { if (left >= right) { return; } // 划分 int mid = left + right >> 1; sort(nums, left, mid); sort(nums, mid + 1, right); // 合并 merge(nums, left, mid, right); } private void merge(int[] nums, int left, int mid, int right) { // 辅助数组 int[] temp = Arrays.copyOfRange(nums, left, right + 1); int leftBegin = 0, leftEnd = mid - left; int rightBegin = leftEnd + 1, rightEnd = right - left; for (int i = left; i <= right; i++) { if (leftBegin > leftEnd) { nums[i] = temp[rightBegin++]; } else if (rightBegin > rightEnd || temp[leftBegin] < temp[rightBegin]) { nums[i] = temp[leftBegin++]; } else { nums[i] = temp[rightBegin++]; } } }
归并排序最吸引人的性质是它能保证将长度为 n 的数组排序所需的时间和 nlogn 成正比;它的主要缺点是所需的额外空间和 n 成正比。
1、空间复杂度:借助辅助数组实现合并,使用 O(n) 的额外空间;递归深度为 logn,使用 O(logn) 大小的栈帧空间。忽略低阶部分,所以空间复杂度为 O(n)
2、非原地排序
3、稳定排序
4、非自适应排序
以上代码是归并排序常见的实现,下面我们来一起看看归并排序的优化策略:
将多次创建小数组的开销转换为只创建一次大数组
在上文实现中,我们在每次合并两个有序数组时,即使是很小的数组,我们都会创建一个新的 temp[] 数组,这部分耗时是归并排序运行时间的主要部分。更好的解决方案是将 temp[] 数组定义成 sort() 方法的局部变量,并将它作为参数传递给 merge() 方法,实现如下:
private void sort(int[] nums, int left, int right, int[] temp) { if (left >= right) { return; } // 划分 int mid = left + right >> 1; sort(nums, left, mid, temp); sort(nums, mid + 1, right, temp); // 合并 merge(nums, left, mid, right, temp); } private void merge(int[] nums, int left, int mid, int right, int[] temp) { System.arraycopy(nums, left, temp, left, right - left + 1); int l = left, r = mid + 1; for (int i = left; i <= right; i++) { if (l > mid) { nums[i] = temp[r++]; } else if (r > right || temp[l] < temp[r]) { nums[i] = temp[l++]; } else { nums[i] = temp[r++]; } } }
当数组有序时,跳过 merge() 方法
我们可以在执行合并前添加判断条件:如果nums[mid] <= nums[mid + 1]时我们认为数组已经是有序的了,那么我们就跳过 merge() 方法。它不影响排序的递归调用,但是对任意有序的子数组算法的运行时间就变成线性的了,代码实现如下:
private void sort(int[] nums, int left, int right, int[] temp) { if (left >= right) { return; } // 划分 int mid = left + right >> 1; sort(nums, left, mid, temp); sort(nums, mid + 1, right, temp); // 合并 if (nums[mid] > nums[mid + 1]) { merge(nums, left, mid, right, temp); } } private void merge(int[] nums, int left, int mid, int right, int[] temp) { System.arraycopy(nums, left, temp, left, right - left + 1); int l = left, r = mid + 1; for (int i = left; i <= right; i++) { if (l > mid) { nums[i] = temp[r++]; } else if (r > right || temp[l] < temp[r]) { nums[i] = temp[l++]; } else { nums[i] = temp[r++]; } } }
对小规模子数组使用插入排序
对小规模数组进行排序会使递归调用过于频繁,而使用插入排序处理小规模子数组一般可以将归并排序的运行时间缩短 10% ~ 15%,代码实现如下:
/** * M 取值在 5 ~ 15 之间大多数情况下都能令人满意 */ private final int M = 9; private void sort(int[] nums, int left, int right) { if (left + M >= right) { // 插入排序 insertSort(nums); return; } // 划分 int mid = left + right >> 1; sort(nums, left, mid); sort(nums, mid + 1, right); // 合并 merge(nums, left, mid, right); } /** * 插入排序 */ private void insertSort(int[] nums) { for (int i = 1; i < nums.length; i++) { int base = nums[i]; int j = i - 1; while (j >= 0 && nums[j] > base) { nums[j + 1] = nums[j--]; } nums[j + 1] = base; } } private void merge(int[] nums, int left, int mid, int right) { // 辅助数组 int[] temp = Arrays.copyOfRange(nums, left, right + 1); int leftBegin = 0, leftEnd = mid - left; int rightBegin = leftEnd + 1, rightEnd = right - left; for (int i = left; i <= right; i++) { if (leftBegin > leftEnd) { nums[i] = temp[rightBegin++]; } else if (rightBegin > rightEnd || temp[leftBegin] < temp[rightBegin]) { nums[i] = temp[leftBegin++]; } else { nums[i] = temp[rightBegin++]; } } }
以上就是一对一直播软件源码,归并排序的优化策略, 更多内容欢迎关注之后的文章