C# 编写一个简单的快速排序例程

这个程序用随机数字组成的同一序列填充一个大型数组,然后使用快速排序例程对这些数字进行排序,并报告所用时间。

图 3 快速排序

  1.           using System;
  2. using System.Threading;
  3. using System.Threading.Tasks;
  4. using System.Diagnostics;
  5.  
  6. namespace ParallelSort {
  7.   class Program {
  8.     // For small arrays, use Insertion Sort
  9.     private static void InsertionSort(
  10.       int[] list, int left, int right) {
  11.  
  12.       for (int i = left; i < right; i++) {
  13.         int temp = list[i];
  14.         int j = i;
  15.  
  16.         while ((j > 0) && (list[j - 1] > temp)) {
  17.           list[j] = list[j - 1];
  18.           j = j - 1;
  19.         }
  20.         list[j] = temp;
  21.       }
  22.     }
  23.  
  24.     private static int Partition(
  25.       int[] array, int i, int j) {
  26.  
  27.       int pivot = array[i];
  28.  
  29.       while (i < j) {
  30.         while (array[j] >= pivot && i < j) {
  31.           j--;
  32.         }
  33.  
  34.         if (i < j) {
  35.           array[i++] = array[j];
  36.         }
  37.  
  38.         while (array[i] <= pivot && i < j) {
  39.           i++;
  40.         }
  41.  
  42.         if (i < j) {
  43.           array[j--] = array[i];
  44.         }
  45.       }
  46.  
  47.       array[i] = pivot;
  48.       return i;
  49.     }
  50.  
  51.     static void QuickSort(
  52.       int[] array, int left, int right) {
  53.  
  54.  
  55.       // Single or 0 elements are already sorted
  56.       if (left >= right)
  57.         return;
  58.  
  59.       // For small arrays, use a faster serial routine
  60.       if ( right-left <= 32) {
  61.         InsertionSort(array, left, right);
  62.         return;
  63.       }
  64.  
  65.       // Select a pivot, then quicksort each sub-array
  66.       int pivot = Partition(array, left, right);
  67.  
  68.       QuickSort(array, left, pivot - 1);
  69.       QuickSort(array, pivot + 1, right);
  70.     }
  71.  
  72.     static void Main(string[] args) {
  73.  
  74.       const int ArraySize = 50000000;
  75.  
  76.       for (int iters = 0; iters < 1; iters++) {
  77.         int[] array;
  78.         Stopwatch stopwatch;
  79.  
  80.         array = new int[ArraySize];
  81.         Random random1 = new Random(5);
  82.  
  83.         for (int i = 0; i < array.Length; ++i) {
  84.           array[i] = random1.Next();
  85.         }
  86.  
  87.         stopwatch = Stopwatch.StartNew();
  88.         QuickSort(array, 0, array.Length - 1);
  89.         stopwatch.Stop();
  90.  
  91.         // Verify it is sorted
  92.         for (int i = 1; i < array.Length; ++i) 
  93.           if (array[i - 1] > array[i - 1]) 
  94.             throw new ApplicationException("Sort Failed");
  95.  
  96.         Console.WriteLine("Serialt: {0} ms",  
  97.            stopwatch.ElapsedMilliseconds);
  98.       }
  99.     }
  100.   }
  101. }
  102.         

如果看一下 QuicSort 函数,您会发现它是以递归方式将数组一分为二,直到达到某个阈值,这时便不再进行细分,而开始对列表进行排序。 如果将这种方式变为并行版本,您只需要更改以下两行即可:

  1.           QuickSort( array, lo, pivot - 1);
  2. QuickSort( array, pivot + 1, hi);
  3.         

以下是并行版本:

  1.           Parallel.Invoke(
  2.   delegate { QuickSort(array, left, pivot - 1); },
  3.   delegate { QuickSort(array, pivot + 1, right); }
  4. );
  5.         

Parallel.Invoke 接口是 .NET 任务并行库中 Systems.Threading.Tasks 命名空间的组成部分。 使用该接口,您可以指定一个以异步方式运行的函数。 在本例中,我通过它将每个排序函数放在单独的线程上运行。

尽管有更高效的方法(只生成一个新线程并使用现有的执行线程对其他子列表进行排序),但我希望保持对称性并说明将串行程序转换为并行程序是多么简单。

posted on 2011-11-18 18:24  thankchunzi  阅读(501)  评论(0编辑  收藏  举报

导航