三路快速排序以及双向扫描改进尝试
三路快速排序用三个指针来标注大于、等于、小于v的区域边界。三路快速排序比较省事的实现是只用一个指针(i)来从左向右遍历判断整个数组,这样在右侧元素大于或小于v的时候都要进行频繁的交换
1 public static void Quick3way1(IComparable[] a) 2 { 3 Q3wPartition(a, 0, a.Length - 1); 4 } 5 6 7 private static void Q3wPartition(IComparable[] a, int lo, int hi) 8 { 9 if (lo >= hi) return; 10 int lt = lo, i = lo + 1, gt = hi; 11 IComparable v = a[lo]; 12 int cmp; 13 14 while (i <= gt) // gt长期指向未处理的数,所以最后一轮i==gt 15 { 16 cmp = a[i].CompareTo(v); // 只用i来扫描判断值大小 17 if (cmp > 0) 18 Swap(a, i, gt--); // 交换完后gt自减,所以gt长期指向未处理的数 19 else if(cmp < 0) 20 Swap(a, lt++, i++); 21 else i++; 22 } 23 Q3wPartition(a, lo, lt - 1); 24 Q3wPartition(a, i, hi); 25 }
尝试用两个指针分别从左右向中间扫描判断,先让左指针开始搜索,当左指针扫描到大于v的值时,等右指针搜索,直到右指针扫描到需要处理的值时才和左指针指向的值交换
1 public static void Quick3way2(IComparable[] a) 2 { 3 Q3w2Partition(a, 0, a.Length - 1); 4 } 5 6 7 public static void Q3w2Partition(IComparable[] a, int lo, int hi) 8 { 9 if (hi <= lo) return; //递归结束 10 11 int lt, gt, i, cmp; 12 lt = lo; 13 i = lo+1; 14 gt = hi; 15 IComparable v = a[lo]; 16 17 while (i <= gt) 18 { 19 cmp = a[i].CompareTo(v); 20 if (cmp == 0) 21 i++; 22 else if (cmp < 0) 23 Swap(a, lt++, i++); 24 else //a[i] > v时,从右开始扫描 25 { 26 while (gt > i) 27 { 28 cmp = a[gt].CompareTo(v); 29 if (cmp == 0) 30 { 31 Swap(a, i++, gt); //a[i],a[gt]一同归位 32 break; 33 } 34 else if (cmp < 0) 35 { 36 IComparable temp = a[gt]; 37 a[gt] = a[i]; 38 a[i++] = a[lt]; 39 a[lt++] = temp; //a[i],a[gt]归位 40 break; 41 } 42 gt--; //cmp>0,a[gt]自然归位,再循环n轮直到找到1个a[gt]<=v为止a[i]归位 43 } 44 gt--; //当gt自减到等于i时,还要再自减一次以退出外循环 45 } 46 } 47 Q3w2Partition(a, lo, lt - 1); 48 Q3w2Partition(a, i, hi); 49 }
测试代码太长,先把主要的贴上来吧
static void Main(string[] args) { SortTest2(); } /// <summary> /// 批量分组测试两种算法 /// </summary> public static void SortTest2() { int scale = 1000000; // 构造10个随机数组并赋值 SortTest[] sortTests = new SortTest[10]; for (int i = 0; i < 10; i++) { sortTests[i] = new SortTest(scale, 1, 1000); } // 构造10个计时器 Stopwatch[] sw = new Stopwatch[10]; for (int i = 0; i < 10; i++) { sw[i] = new Stopwatch(); } // 前5个用来测试第一个算法,后5个测试第二个 Console.WriteLine("Q3way1: "); for (int i = 0; i < 5; i++) { sw[i].Start(); QuickSort.Quick3way1(sortTests[i].Arr); // 实现1 sw[i].Stop(); Console.Write($"\t[{i}]Array is sorted: " + sortTests[i].IsSorted()); Console.WriteLine("\tspends: " + sw[i].Elapsed); } Console.WriteLine("\nQ3way2: "); for (int i = 5; i < 10; i++) { sw[i].Start(); QuickSort.Quick3way2(sortTests[i].Arr); // 实现2 sw[i].Stop(); Console.Write($"\t[{i}]Array is sorted: " + sortTests[i].IsSorted()); Console.WriteLine("\tspends: " + sw[i].Elapsed); } } /// <summary> /// 生成随机整数组成的IComparable数组 /// </summary> /// <param name="a"></param> /// <param name="scale"></param> /// <param name="minValue"></param> /// <param name="maxValue"></param> public static void GetRandomArray(IComparable[] a, int scale, int minValue, int maxValue) { if (a.Length < scale) return; // 用系统时间作为随机种子 Random rd = new Random(unchecked((int)DateTime.Now.Ticks)); for (int i = 0; i < scale; i++) { a[i] = rd.Next(minValue, maxValue); } } /// <summary> /// 检验数组是否升序 /// </summary> /// <param name="a"></param> /// <returns></returns> public bool IsSorted() { for (int i = 1; i < arr.Length; i++) { if (arr[i].CompareTo(arr[i - 1]) < 0) return false; } return true; }
看起来有那么一点点点点点提升了

浙公网安备 33010602011771号