快速排序在实际应用中会面对大量具有重复元素的数组。相比原生的快排,有巨大的改进潜力。(从O(nlgn)提升到O(n))
E.W.Dijlstra(对,就是Dijkstra最短路径算法的发明者)提出的算法是:
对于每次切分:从数组的左边到右边遍历一次,维护三个指针,其中lt指针使得元素(arr[0]-arr[lt-1])的值均小于切分元素;gt指针使得元素(arr[gt+1]-arr[N-1])的值均大于切分元素;i指针使得元素(arr[lt]-arr[i-1])的值均等于切分元素,(arr[i]-arr[gt])的元素还没被扫描,切分算法执行到i>gt为止。每次切分之后,位于gt指针和lt指针之间的元素的位置都已经被排定,不需要再去处理了。之后将(lo,lt-1),(gt+1,hi)分别作为处理左子数组和右子数组的递归函数的参数传入,递归结束,整个算法也就结束。
//
/// 快速排序在实际应用中会面对大量具有重复元素的数组。相比原生的快排,有巨大的改进潜力。(从O(nlgn)提升到O(n))
/// E.W.Dijlstra(对,就是Dijkstra最短路径算法的发明者)提出的算法是: 对于每次切分:从数组的左边到右边遍历一次,维护三个指针,
/// 其中lt指针使得元素(arr[0]-arr[lt-1])的值均小于切分元素;gt指针使得元素(arr[gt+1]-arr[N-1])的值均大于切分元素;
/// i指针使得元素(arr[lt]-arr[i-1])的值均等于切分元素,(arr[i]-arr[gt])的元素还没被扫描,切分算法执行到i>gt为止。
/// 每次切分之后,位于gt指针和lt指针之间的元素的位置都已经被排定,不需要再去处理了。
/// 之后将(lo,lt-1),(gt+1,hi)分别作为处理左子数组和右子数组的递归函数的参数传入,递归结束,整个算法也就结束。
///
///
///
/// arr.Length - 1
private static void QuickSort_Optimization(int[] arr, int low, int hi)
{
//去除单个元素或者没有元素的情况
if (low < hi)
{
int lt = low;
int i = low + 1;//第一个元素是切分元素,所以i从low+1开始
int gt = hi;
int pivot = arr[lt];
while (i <= gt)
{
//小于切分元素放在lt左边,指针lt和i整体右移
if (arr[i] < pivot)
{
Swap(ref arr[i], ref arr[lt]);
i++;
lt++;
}
//大于切分元素放在gt右边,指针gt左移
else if (arr[i] > pivot)
{
Swap(ref arr[i], ref arr[gt]);
gt–;
}
//等于切分元素,指针i++
else
{
i++;
}
}
//lt-gt之间的元素已经排定,只需对lt左边和gt右边的元素进行递归排序
//对比新的轴小的部分递归排序
QuickSort_Optimization(arr, low, lt - 1);
//对比新的轴大的部分递归排序
QuickSort_Optimization(arr, gt + 1, hi);
}
}