一、分析快速排序的时间复杂度:
最优的情况:
每次选到的基准值能把待排序的的数组平均分
这种情况下的时间复杂度为 O(𝑛log⋅𝑛)
最差的情况:
每次选到的数都是最小或着最大的数
只是把数组分成了( 空 基准值 n-1) 三个部分
这样情况下的时间复杂度为 O(𝑛^2)
具体的分析请看下图:
二、解决问题
通过上图我们发现是由于基准值的选择而导致了效率的不稳定
那我们就对之前选数的方法进行修改
1)两种修改方法
1.随机选数(随机选择数字作为基准值)
2.三数取中(在left right mid 中取中间值为基准值)
2)代码实现
******************************************随机选数***********************************************
//随机选数
int randKey(int* a, int left, int right)
{
int r = rand() % right+1;//0~right
int rKey = r >= left ? r : r + (right - left)+1;
return rKey;
}
******************************************三数取中************************************************
//三数取中
int Midi(int* a, int left, int right)
{
int mid = (left + right) / 2;
//left>=mid
if (a[left] >= a[mid])
{
//left>=mid>=right
if (a[mid] >= a[right])
return mid;
//left ? right >mid
else if (a[left] > a[right])
return right;
else
return left;
}
//left<mid
else
{
//left<mid<right
if (a[mid] <= a[right])
return mid;
else if (a[right] >= a[left])
return right;
else
return left;
}
}
三、新的问题
1)问题分析
如果数组中的值全部相等或存在大量相同的数,那么上面两种方法的优化就十分微弱
时间时间效率会向最坏的方向走。
我们之前是把数组分为 【小于】 【大于】
如果有大量相同的数我们就应再加一个区间 【大于】 【等于】 【小于】
2)代码实现
代码的实现结合了最基本的方法和前后指针法
不会的同学可以看这里:
基本方法:
前后指针法:
//三段区间
void QuickSort(int* a, int begin, int end)
{
if (begin >= end)
return;
int key = a[begin];
int left = begin;
int right = end;
int cur = left + 1;
while (cur<=right)
{
if (a[cur] > key)
{
Swap(&a[cur], &a[right]);
right--;
}
else if (a[cur] < key)
{
Swap(&a[cur], &a[left]);
cur++;
left++;
}
else
{
cur++;
}
}
// begin left right end
QuickSort2(a, begin, left-1);
QuickSort2(a, right+1, end);
}
四 、结语
以上就是对快速排序的优化,若有错误,还望指出。
关于快速排序,作者的主页有着详细的介绍,包括三种不同的方法。
你的点赞和关注是作者前进的动力!
最后,作者主页有许多有趣的知识,欢迎大家关注作者,作者会持续更新有意思的代码,在有趣的玩意儿中成长!