🥰作者: FlashRider
🌏专栏: 初阶数据结构
🍖知识概要:快速排序在某些特定情况下时间复杂度会降为O(n²),我们就来探讨一下在这些情况下如何优化快速排序的时间复杂度。
目录
有序序列——取中为key
对于有序的序列,快速排序每一趟如果选最左端点为key,那么排完一趟后比key小的数为0个,所以会浪费很多性能,而且这样选n次key,那么时间复杂度就会降低为n²。
对于有序序列的优化就是,我们可以将mid取为key,不要每次选最大或最小的为key即可。
//取key方式1 直取mid
int key = left + right >> 1;//等价于(left + right)/2
//取key方式2 三数取中
int get_key(int a[], int left, int right)
{
int mid = (left + right) / 2;
if (a[left] < a[mid])
{
if (a[mid] < a[right])
{
return mid;
}
else if (a[left] < a[right])
{
return right;
}
else
{
return left;
}
}
else // a[left] > a[mid]
{
if (a[mid] > a[right])
{
return mid;
}
else if (a[left] > a[right])
{
return right;
}
else
{
return left;
}
}
}
int key = get_key(a, left, right);
相同序列——三路划分
Left Right Current 三个指针。
取left为key 则cur == key cur++。
cur < key 与left交换且cur++ left++ cur>key 与right交换且right-- cur不++ (因为要使得left永远指向与key相等的值)
cur 与 right 过之交臂(cur > right)时结束,此时left和right在等于key区间的左右端点处。
最终呈现 小于key 等于key 大于key 的三个区间。
left左边为左区间 right右边为右区间
void QuickSort(int* a, int begin, int end)
{
if(begin >= end) return;
int left = begin, right = end;
int cur = begin + 1;
int key = get_key();//详见三数取中
while(cur < right)
{
if(a[cur] == key) cur++;
else if(a[cur] < key) swap(a[cur++], a[left++]);
else swap(a[cur], a[right--]);
}
QuickSort(a, begin, left);
QuickSort(a, right, end);
}
综合优化——最优美的快排
void sort(int q[], int l, int r)//需要考虑边界问题
//(没有用key作下标, 递归用的i和j,需要考虑key本身位置)
{
if(l >= r) return;
int x = q[l];
int i = l - 1, j = r + 1;
while(i < j)
{
do i++; while(q[i] < x);
do j--; while(q[j] > x);
if(i < j)
swap(q[i], q[j]);
}
sort(q, l, j), sort(q, j + 1, r);
}