使用语言:c语言,编译器visual studio 2017
一.基本思想
假设由小到大排序。则快速排序的基本思想是,用一个左指针(或下标)记录最左边的数,用一个右指针记录最右边的数。选取一个数作为基数(随机取即可,我取的是第一个数),实现基数左边的都不大于基数,基数右边的都不小于基数,再递归地分别对基数左右的数进行快速排序,最后得到排序完毕的序列。具体实现过程:
(1)设数组为array[],设左下标为i,右下标为j,以array[i]为基数;
(2)首先j向左遍历,找到不大于基数的数就停止;
(3)i向右遍历,找到不小于基数的数就停止;
(4)交换array[i]和array[j]的位置,交换后基数需要设置成array[j];//这样确保基数是同一个数
(5)循环执行(2)、(3)、(4),直到i和j相等。
二.代码实现
#include<stdio.h>
using namespace std;
void swap(int i, int j, int array[]) {//交换array[i]和array[j]
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
//left向右查找不小于基准的数;right向左查找不大于基准的数
void QuickSort(int left,int right, int array[]) {
int i = left;
int j = right;
int base = array[i];
if (left >= right) return;
while (i != j) {
while (j > i&&array[j] >= base) {
j--;
}
swap(i, j, array);
base = array[j];
while (i < j&&array[i] <= base) {
i++;
}
swap(i, j, array);
base = array[i];
}
QuickSort(left, i - 1, array);
QuickSort(i + 1, right, array);
}
int main()
{
int array[100];
int i = 0;
int j = 0;
int num = 0;
printf("请输入待排序的数字个数:\n");
scanf_s("%d", &num);
printf("请输入%d个数字:\n", num);
for (i; i<num; i++) scanf_s("%d", &array[i]);
i = 0;
j = num - 1;
QuickSort(i, j, array);
for (int k = 0; k < num; k++) {
printf("%d ", array[k]);
if (k == num - 1) printf("\n");
}
return 0;
}
三.时间复杂度分析
这里参考博客surgewong的博客
当基数不能很好的分割序列,比如分割后的两个序列分别拥有1个和n-1个元素,那么快速排序就退化成冒泡排序,这是最差的情况,时间复杂度为O(N^2)。
设T(n)为对n个记录进行排序所需要的时间,则每当一个记录得到其正确位置,整组大致分成两个相等的两部分时,我们得到快速排序算法的最佳时间复杂性:
T(n) <= cn + 2T(n/2) c是一个常数
<= cn + 2(cn/2+2T(n/4)) = 2cn+ 4T(n/4)
<= 2cn + 4(cn/4+ 2T(n/8)) = 3cn + 8T(n/8)
…… ……
<= cnlogn + nT(1) = O(nlogn) 其中cn 是一次划分所用的时间,c是一个常数
最坏的情况,每次划分都得到一个子序列,时间复杂度为:
T(n) = cn + T(n-1)
= cn + c(n-1) + T(n - 2) = 2cn -c + T(n-2)
= 2cn - c + c(n-2) + T(n-3)= 3cn - 3c + T(n-3)
……
= c[n(n+1)/2-1] + T(1) = O(n2)
快速排序的时间复杂度在平均情况下介于最佳与最差情况之间,假设每一次分割时,基准值处于最终排序好的位置的概率是一样的,基准值将数组分成长度为0 和 n-1,1 和 n-2,……的概率都是 1/n。在这种假设下,快速排序的平均时间复杂性为:
T(n) = cn + 1/n(T(k)+ T(n-k-1)) T(0) = c, T(1) = c
这是一个递推公式,T(k)和T(n-k-1)是指处理长度为 k 和 n-k-1 数组是快速排序算法所花费的时间, 根据公式所推算出来的时间为 O(nlogn)。因此快速排序的平均时间复杂性为O(nlogn)。