c# 归并排序,递归实现和非递归实现
归并排序的策略是建立在对两个有序数列合并的基础上的:
先看看怎样对两个有序的数列合并:(left~center有序,center+1~rightEnd有序)
主要采用双游标法:
private static void MergeSorted(int[] nums,int left,int center,int rightEnd) { int right = center + 1; int tempPoint = 0; int[] tempList = new int[rightEnd - left + 1]; while (left <= center && right <= rightEnd) { if (nums[left] <= nums[right]) { tempList[tempPoint++] = nums[left++]; } else tempList[tempPoint++] = nums[right++]; } while (left <= center) { tempList[tempPoint++] = nums[left++]; } while (right <= rightEnd) { tempList[tempPoint++] = nums[right++]; } //再给nums重新赋值; tempPoint--; while(tempPoint>=0) { nums[rightEnd--] = tempList[tempPoint--]; } }
有了这个工具就很容易实现递归实现了,递归基是数组中仅有一个元素,什么操作都不用做,故此可省略
然后尽量将数组长度尽量均分,尽快缩小问题规模,分而治之,分别处理好规模较小的问题后,就是调用上述合并方法.
private static void m_Merge_Sort(int[] nums,int start,int end) { if (start != end) { int center = (start + end) / 2; m_Merge_Sort(nums, start, center); m_Merge_Sort(nums, center + 1, end); MergeSorted(nums, start, center, end); } } public static void Merge_Sort(int[] nums) { int end = nums.Length - 1; m_Merge_Sort(nums, 0, end); }
非递归实现策略:
递归实现的思路是通常是自顶而下,非递归实现的思路就是自底而上:
先将数列看成长度为1的n个有序数列,两两合并成长度为2的n/2个,再两两合并成长度为4的,n/4个...
值得注意的是细节,数列个数并不总是是2^n,最后那个或者最后两个数列需要单独考虑.
private static void Merge_Pass(int[] nums,int stepLength) { int numsLength = nums.Count(); int i = 0; while(i <=numsLength - 2 * stepLength) { MergeSorted(nums, i, i + stepLength - 1, i + 2 * stepLength - 1); i += 2 * stepLength; }//注意跳出循环后,i是最后一个合法值+2*stepLength. //判断剩下的数字是否够分成两个有序数组 if (numsLength - i > stepLength)//说明剩下的数字个数能够分成两个有序数列 MergeSorted(nums, i, i + stepLength - 1, numsLength - 1); } public static void NoRecursionMerge_Sort(int[] nums) { int step = 1; while (step <nums.Length) { Merge_Pass(nums, step); step *= 2; } }