前言:
快速排序之所以比较快,是因为与冒泡排序相比,每次的交换时跳跃式的,每次排序的时候设置一个基准点(Pivot)
将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。
这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。
因此总的比较和交换次数就少了,速度自然就提高了。
当然在最坏的情况下,仍可能是相邻的两个数进行了交换。
因此快速排序的最差时间复杂度和冒泡排序是一样的都是O(n^2)
它的平均时间复杂度为O(n*log2(n));
下面我会一步一步将步骤写出来:
我们要对数组a[]={4,18,6,2,1,5,7,44,3,685}进行排序
选取Pivot=a[0]=4;
由于选取左端点为Pivot,我们要从右边开始进行排序
j=9 a[9]=685>=Pivot=4 j-- ;
j=8 a[8]=3<Pivot 循环停止 接下来从i开始
i=0 a[0]<=Pivot=4 i++
i=1 a[1]=18>Pivot 循环停止 交换 a[i] 与a[j]
接下来继续从j开始
j=8 a[8]=18>=Pivot=4 j--
j=7 a[7]=44>=Pivot=4 j--
j=6 a[6]=7>=Pivot=4 j--
j=5 a[5]=5>=Pivot=4 j--
j=4 a[4]=1<Pivot=4 循环停止 接下来从i开始循环
i=1 a[1]=3<=4 i++
i=2 a[2]=6 >4 循环停止 交换a[i]与a[j]
接下来继续从j开始
j=4 a[4]=6>=Pivot=4 j--
j=3 a[3]=2<4 循环停止 接下来从i开始
i=2 a[2]=2<4 i++
此时i=j=3 整个循环停止 将Pivot的值与a[i]对应的数组值交换
至此 i=3 左边的数组恒小于等于4 ,右边的数组恒大于等于4;
接下来进行下一轮循环分别从0-2和4-9再按照上图的规律进行排序
下面给出具体代码
Code:
#include<iostream>
using namespace std;
void quicksort(int arry[], int begin, int end);
void swap(int* x, int* y);
void insertsort(int a[], int n);
int a[4]={1232,1,34,5};
int main() {
quicksort(a, 0, 3);
for (int i = 0; i < 4; i++)
cout << a[i]<<" ";
return 0;
}
void quicksort(int arry[], int begin, int end) {
if (begin >= end)
return; //一定要加的条件,否则函数会不停的循环。
int i = begin;
int j = end;
int Pivot = arry[begin];
while (i != j) { //每次i与j相遇时,交换i或j对应的数组值与Pivot;
while (arry[j] >= Pivot && j > i)
j--;
while (arry[i] <= Pivot && j > i)
i++;
if (j > i) {
int temp = arry[i];
arry[i] = arry[j];
arry[j] = temp;
}
} //至此循环结束 此时i=j;交换i与Pivot的值,开始下一轮循环。
arry[begin] = arry[i];
arry[i] = Pivot;
quicksort(arry, begin, i - 1);
quicksort(arry, i + 1, end);
}
我们可以做一点小优化 即:定义一个swap函数用来交换对应的值,修改版如下:
void quicksort(int arry[], int begin, int end) {
if (begin >= end)
return; //一定要加的条件,否则函数会不停的循环。
int i = begin;
int j = end;
int pivot = arry[begin];
while (i != j) { //每次i与j相遇时,交换i或j对应的数组值与Pivot;
while (arry[j] >=pivot && j > i)
j--;
while (arry[i] <=pivot && j > i)
i++;
if (j > i)
swap(&arry[i], &arry[j]);
} //至此循环结束 此时i=j;交换i与Pivot的值,开始下一轮循环。
swap(&arry[i], &arry[begin]);
quicksort(arry, begin, i - 1);
quicksort(arry, i + 1, end);
}
void swap(int* x, int* y) {
int temp = *x;
*x = *y;
*y = temp;
}
但是可以更快一些,要如何实现呢?
No1:随机化:
如果永远取第一个元素作为枢轴的话,在数组已经有序的情况下每次划分都将得到最坏的结果,时间复杂度退化为O(n^2)。因为其中一个子序列每次都只比原序列少一个元素,该侧的递归深度将达到最大。然而,我们可以通过随机选取枢轴元素来打破这种固定模式,这样每次都是最坏划分的概率就非常小了。实现起来只需要先将随机选中的元素和第一个元素交换一下位置作为枢轴元素,然后就可以接着用原来的方法进行排序了。
Code:
void quicksort(int arry[], int begin, int end) {
if (begin >= end)
return; //一定要加的条件,否则函数会不停的循环。
int i = begin;
int j = end;
int pivot = rand()%(end-begin+1) + begin;
swap(&arry[begin], &arry[pivot]);
while (i != j) { //每次i与j相遇时,交换i或j对应的数组值与Pivot;
while (arry[j] >=arry[begin] && j > i)
j--;
while (arry[i] <=arry[begin] && j > i)
i++;
if (j > i)
swap(&arry[i], &arry[j]);
} //至此循环结束 此时i=j;交换i与Pivot的值,开始下一轮循环。
swap(&arry[i], &arry[begin]);
quicksort(arry, begin, i - 1);
quicksort(arry, i + 1, end);
}
void swap(int* x, int* y) {
int temp = *x;
*x = *y;
*y = temp;
}
No2:小区间插入排序。
当序列长度分割到足够小后,继续使用快速排序递归分割的效率反而没有直接插入排序高
因此我们可以增加一个判断,当区间长度小于10以后改为使用插入排序。
Code:
void quicksort(int arry[], int begin, int end) {
if (begin >= end)
return; //一定要加的条件,否则函数会不停的循环。
if ((end - begin + 1) < 10) {
insertsort(arry, end);
}
int i = begin;
int j = end;
int pivot = rand() % (end - begin + 1) + begin;
swap(&arry[begin], &arry[pivot]);
while (i != j) { //每次i与j相遇时,交换i或j对应的数组值与Pivot;
while (arry[j] >= arry[begin] && j > i)
j--;
while (arry[i] <= arry[begin] && j > i)
i++;
if (j > i)
swap(&arry[i], &arry[j]);
} //至此循环结束 此时i=j;交换i与Pivot的值,开始下一轮循环。
swap(&arry[i], &arry[begin]);
quicksort(arry, begin, i - 1);
quicksort(arry, i + 1, end);
}
void swap(int* x, int* y) {
int temp = *x;
*x = *y;
*y = temp;
}
void insertsort(int a[], int n) {
for (int i = 1; i < n; i++) {
int key = a[i];
int j = i - 1;
while (j >= 0 && a[j] > key) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = key;
}
}
至此更快的快速排序就出现了,下面给出完整版代码:
#include<iostream>
using namespace std;
void quicksort(int arry[], int begin, int end);
void swap(int* x, int* y);
void insertsort(int a[], int n);
int a[10]={4,18,6,2,1,5,7,44,3,685};
int main() {
quicksort(a, 0, 9);
for (int i = 0; i < 10; i++)
cout << a[i]<<" ";
return 0;
}void quicksort(int arry[], int begin, int end) {
if (begin >= end)
return; //一定要加的条件,否则函数会不停的循环。
if ((end - begin + 1) < 10) {
insertsort(arry, end);
}
int i = begin;
int j = end;
int pivot = rand() % (end - begin + 1) + begin;
swap(&arry[begin], &arry[pivot]);
while (i != j) { //每次i与j相遇时,交换i或j对应的数组值与Pivot;
while (arry[j] >= arry[begin] && j > i)
j--;
while (arry[i] <= arry[begin] && j > i)
i++;
if (j > i)
swap(&arry[i], &arry[j]);
} //至此循环结束 此时i=j;交换i与Pivot的值,开始下一轮循环。
swap(&arry[i], &arry[begin]);
quicksort(arry, begin, i - 1);
quicksort(arry, i + 1, end);
}
void swap(int* x, int* y) {
int temp = *x;
*x = *y;
*y = temp;
}
void insertsort(int a[], int n) {
for (int i = 1; i < n; i++) {
int key = a[i];
int j = i - 1;
while (j >= 0 && a[j] > key) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = key;
}
}