昨晚看到一个帖子, 说的是三行代码实现快速排序, 文中实现Quick Sort代码如下:
public static IEnumerable<T> QuickSort<T>(IEnumerable<T> list) where T : IComparable<T> { if (list.Count() <= 1) return list; var pivot = list.First(); return QuickSort(list.Where(x => x.CompareTo(pivot) < 0)) .Concat(list.Where(x => x.CompareTo(pivot) == 0)) .Concat(QuickSort(list.Where(x => x.CompareTo(pivot) > 0))); }
不由想起老赵两年前(正好整整两年)的一个帖子: 趣味编程:函数式链表的快速排序. 虽说在LINQ技术下, 三行代码是可以将快速排序的思路很直白明了的呈现出来, 这是函数式编程的优点. 看到这段代码里三个Where, 我心里不免有些疑问, Where不就枚举了整个链表了么, 这样做还是所谓的"Quick Sort"吗. 因此我用老赵的CodeTimer测试了一下它的性能, 并与传统的快速排序做个比较.
传统的的Quick Sort算法摘自维基百科:
public static void Sort(int[] numbers) { Sort(numbers, 0, numbers.Length - 1); } private static void Sort(int[] numbers, int left, int right) { if (left < right) { int middle = numbers[(left + right) / 2]; int i = left - 1; int j = right + 1; while (true) { while (numbers[++i] < middle) ; while (numbers[--j] > middle) ; if (i >= j) break; Swap(numbers, i, j); } Sort(numbers, left, i - 1); Sort(numbers, j + 1, right); } } private static void Swap(int[] numbers, int i, int j) { int number = numbers[i]; numbers[i] = numbers[j]; numbers[j] = number; }
由于CodeTimer最后一个参数是一个Action委托, 我对两种快速排序算法包装了一下, 然后测试的时候就执行这两个方法:
public static void FunctionalQuickSort() { int[] array = new int[] { 49, 38, 65, 97, 76, 13, 27 }; QuickSort(array); } public static void NormalQuickSort() { int[] array = new int[] { 49, 38, 65, 97, 76, 13, 27 }; Sort(array); }
调用CodeTimer的Time方法, 就可以得到性能数据:
//参数分别为: 输出的方法名字, 方法执行次数, 方法体 CodeTimer.Time("Functional Quick Sort", 10000, () => FunctionalQuickSort()); CodeTimer.Time("Normal Quick Sort", 10000, () => NormalQuickSort());
做了几次测试, 得到的测试数据基本上是这个情况:
这还只是7个数据的排序, 如果数据越多, 用LINQ写出来的算法性能劣势就越明显.
另外我发现百度里讲解快速排序的算法过程真是坑爹, 我看了一下它那个过程, 觉得好像有点不对头, 自己在纸上又画了一遍, 真不明白它这句"此时再执行第三步的时候就发现 i=j, 从而结束一趟快速排序"是怎么来的...第一趟排序什么时候 i=j 过的...
步骤 | 序列 | i | j |
---|---|---|---|
0 | 49 38 65 97 76 13 27 | 0 | 6 |
1 | 49 38 65 97 76 13 27 | 0 | 6 |
2 | 27 38 65 97 76 13 49 | 2 | 6 |
3 | 27 38 49 97 76 13 65 | 2 | 5 |
4 | 27 38 13 97 76 49 65 | 3 | 5 |
5 | 27 38 13 49 76 97 65 | 3 | 2 |
由此看来, 一方面是简洁的书写代码, 另一方面是性能的考量, 您会选择哪种呢?