快速排序的时间复杂度
void Swap(int* a, int* b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void QuickSort1(int* a, int left, int right)
{
int begin = left;
int end = right;
int keyi = begin;
if (begin >= end)
return;
while (left <right)
{
while (left < right && a[right] >= a[keyi])
{
right--;
}
while (left<right && a[left]<=a[keyi])
{
left++;
}
Swap(&a[left], &a[right]);
}
Swap(&a[keyi], &a[left]);
keyi = left;
QuickSort1(a, begin, keyi - 1);
QuickSort1(a, keyi + 1, end);
}
快速排序最坏情况
当序列有序时,快速排序时间复杂度最高为n方
如图片所示,当序列有序时二叉树没有左侧节点,只有右侧节点,高度为n,每层为n、n-1、
n-2……1,计算可得时间复杂度约为O(N^2)。
快排的一般情况
当序列无序时,快排的时间复杂度为O(N*logN)。
具体分析需要用到二叉树的内容,二叉树中完全二叉树的高度为log(N+1),每层时间复杂度约为N,所以整体的时间复杂度约为O(N*logN)。
本节重点是理解快排的最坏情况,为后面的优化做铺垫,一般情况,大家可以根据二叉树的内容还有快排的逻辑来推算。
快排的优化(如何避免最坏情况的出现)
随机数法
随机数法用到了rand()函数,头文件为<stdlib.h>
由于在最坏情况时,基准值的选取总是从最小的数开始选取,导致树的高度为n,因此我们随机选取基准值,然后将选取的基准值与left互换,其他操作不变。
其中有一些细节,right-left+1是为了防止数组越界,把randi控制在n中,randi+=left是为了将randi控制在left与right范围中。
void QuickSort1(int* a, int left, int right)
{
if (left >=right)
return;
//随机数
int randi = rand();
//使随机数大小不超过n
randi %= (right - left + 1);
//保证随机数在left到right范围里
randi += left;
Swap(&a[randi], &a[left]);
int begin = left;
int end = right;
int keyi = left;
while (left <right)
{
while (left < right && a[right] >= a[keyi])
{
right--;
}
while (left<right && a[left]<=a[keyi])
{
left++;
}
Swap(&a[left], &a[right]);
}
Swap(&a[keyi], &a[left]);
keyi = left;
QuickSort1(a, begin, keyi - 1);
QuickSort1(a, keyi + 1, end);
}
三数取中法
具体思路:引入变量mid,将基准值选择在mid位置,mid的算法是(left+right)/2,这样也能避免最坏情况的出现。
int GetMid(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 left;
else return right;
}
else {
if (a[mid] > a[right])
return mid;
else if (a[left] > a[right])
return left;
else return right;
}
}
void QuickSort1(int* a, int left, int right)
{
if (left >=right)
return;
int mid = GetMid(a,left,right);
Swap(&a[mid], &a[left]);
int begin = left;
int end = right;
int keyi = left;
while (left <right)
{
while (left < right && a[right] >= a[keyi])
{
right--;
}
while (left<right && a[left]<=a[keyi])
{
left++;
}
Swap(&a[left], &a[right]);
}
Swap(&a[keyi], &a[left]);
keyi = left;
QuickSort1(a, begin, keyi - 1);
QuickSort1(a, keyi + 1, end);
}
快速排序的空间复杂度
快速排序Hoare版本的空间复杂度为O(logN)-O(N),一般情况为O(logN),最坏情况(序列有序时)为O(N)。