快速排序是对冒泡排序的一种改进。它的基本思想是:通过一躺排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据段变成有序序列。
过程:
每趟调用都要选择一个基准元素,将待处理段按这个基准数据进行划分,即左边的元素都小于等于基准元素,而右边都大于等与基准元素.
针对下面的算法,注意扫描过程是右->左->右->左....这样交替进行的, 算法首先把基准元素保存到temp中,这样数组就空出一个位置了(i 指向的位置) ,接着从右边开始扫描寻找比temp小的元素,找到后将元素覆盖到 i 指向的位置(i 中的元素已经放到temp中了),接着换左边开始扫描(i中元素是有效数据,这时j 指向的空间是交换空间),左边扫描时逐1增加i的数值,直到找到一个Array[i]>temp,将array[i]保存到arra[j]中,j 指向的空间是交换空间,接着再换右边开始扫描,如果到i=j都没找到符合条件的元素就表示i(i=j)位置就是temp元素应该存放的位置了,上面过程可以看到i或j其中必然有一个指向交换空间(元素已经被移动,里面的内容没有意义了,在C#的引用类型中这个就是一个指针数据)而当i=j时可以放心的执行array[i]=temp 或array[j]=temp 操作,将基准元素放会到数组排序后对应的位置.
关键点: 选择基准元素是随机的(一般是第一个)因此这个元素的位置是不确定的,(不要老以为它应该放到数组的中间位置),而上面的操作实质上都是围绕给基准元素找到一个合适位置进行的,执行上面描述的过程后, 只要基准元素找到位置则可. 比方数组的第一个元素是23,而23是数组的最小元素,那么根据上面过程执行后会发现最后i=j=0, 那么array[i]=temp 将把23放回array[0]位置.这样继续递归时左边的递归调用直接返回,而右边则是少一个元素的QuickSort.
说明: 快速排序是不稳定排序,即两个等价元素其先后(左右)位置与排序前不统一,比方 x1,.....x2 ,排序后有可能是 ...x2,x1...,这样的形式.
C#代码实现
-----------------------------------------
public class QuickSort<T>
{
public static void Sort(T[] array, IComparer<T> comparer)
{
Sort(array, 0, array.Length - 1, comparer);
}
/// <summary>
/// 注意这里注意扫描过程的处理
/// 元素移动后,那么它原来的位置就用来当临时空间来使用了
/// 而i或j其中一个始终指向这个临时空间,当i=j时,表示扫描结束
/// 最后array[i]=temp,将选择的中间元素放回到数组里(排序后对应的位置)
/// </summary>
/// <param name="array"></param>
/// <param name="L"></param>
/// <param name="h"></param>
/// <param name="comparer"></param>
private static void Sort(T[] array, int L, int h, IComparer<T> comparer)
{
T temp;
int i, j;
if (L < h)//至少有2个元素
{
//选择第一个元素为基准元素,从右开始扫描
temp = array[L]; i = L; j = h;
while (i < j)
{
//选择 array[j] < temp的元素,将其移动到前面 i 指向的位置
//而移动后的空间可空出来做下次交换使用,这时j为这个空间的下标
while (i < j && comparer.Compare(temp, array[j]) <= 0) j--;
//i<j 表示找到一个小于temp的元素
if (i < j) array[i] = array[j];
//从左边开始扫描大于temp的元素
while (i < j && comparer.Compare( array[i],temp) <= 0) i++;
//i< j表示找到一个大与
if (i < j) array[j] = array[i];
}
//这里有i=j;temp元素找到自己的位置了,
//左变的都比temp小,右边的都比temp大(或者等于)
array[i] = temp;
Sort(array, L, i - 1, comparer);//完成左边
Sort(array, i + 1, h, comparer);//完成右边
}
}
}
------------------------------
另外在.net2.0中的很多集合类其中的Sort方法使用的都是快速度排序实现的,因此进行集合排序时不需要自己专门实现这么个排序方法.
从Reflector摘录的部分代码
---------------------------------
private void QuickSort<TValue>(T[] keys, TValue[] values, int left, int right, IComparer<T> comparer)
{
do
{
int a = left;
int b = right;
int num3 = a + ((b - a) >> 1); //中间值下标,等价于 a+ (b-a)/2
this.SwapIfGreaterWithItems<TValue>(keys, values, comparer, a, num3);
this.SwapIfGreaterWithItems<TValue>(keys, values, comparer, a, b);
this.SwapIfGreaterWithItems<TValue>(keys, values, comparer, num3, b);
T y = keys[num3];
.............................
这里在排序前先进行"三者取中",即比较这3个元素的大小取中间值做为基准,另外上面类的扫描过程不是交替进行的,而是两边同时扫描(可能找到2个后互换),具体参考Reflector后的代码,下面给出链接中的算法分析有"三者取中"的说明.
参考
快速排序算法原理与实现
算法分析(网站名称: 数据结构)