快速排序(Quicksort)是对冒泡排序的一种改进。
快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
算法流程
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
- (1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
- (2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
- (3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
- (4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它左边,所有比它大的数都放到它右边,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
性能分析
快速排序的一次划分算法从两头交替搜索,直到low和hight重合,因此其时间复杂度是O(n);而整个快速排序算法的时间复杂度与划分的趟数有关。
理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log2n趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O(n log n)。
最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n^2)。
为改善最坏情况下的时间性能,可采用其他方法选取中间数。通常采用“三者值取中”方法,即比较H->r[low].key、H->r[high].key与H->r[(low+high)/2].key,取三者中关键字为中值的元素为中间数。
可以证明,快速排序的平均时间复杂度也是O(n log n)。因此,该排序方法被认为是目前最好的一种内部排序方法。
从空间性能上看,尽管快速排序只需要一个元素的辅助空间,但快速排序需要一个栈空间来实现递归。最好的情况下,即快速排序的每一趟排序都将元素序列均匀地分割成长度相近的两个子表,所需栈的最大深度为log (n+1);但最坏的情况下,栈的最大深度为n。这样,快速排序的空间复杂度为O(log n)。
#include <iostream>
using namespace std;
void myQsort(int arr[], int low, int high)
{
//还有一个先决条件!
if (low >= high) return;
int key = arr[low];
int i = low;
int j = high+1;
while (true)
{
//从左往右找,找到大于key的值时的i,
while (arr[++i] < key)
{
if (i == high) break;
}
//从右往左找,找到小于key的值时的j
while (arr[--j] > key) {
if (j == low) break;
}
if (i >= j) break;
//交换i和j的值
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//交换key和j的值,j此时的值为最右边的小于key的值
int temp = arr[j];
arr[j] = arr[low];
arr[low] = temp;
//做递归
myQsort(arr, low, j - 1);
myQsort(arr, j + 1, high);
}
int main(void) {
int arr[] = { 2,5,66,9,8,1,2,99,3 };
myQsort(arr, 0, sizeof(arr) / sizeof(int) - 1);
for(int x:arr)
cout << x << " " ;
cout << "" << endl;
return 0;
}
第二种写法:
#include <iostream>
#include <vector>
using namespace std;
void myQsort(vector<int> &arr, int left, int right) {
//递归终止条件判断,right 为长度
if (left >= right - 1) {
return;
}
int first = left, last = right - 1, key = arr[left];
while (first < last) {
//从右往左,寻找小于key的数
while (first < last && arr[last] >= key)
{
--last;
}
arr[first] = arr[last];
//从左往右,寻找大于key的数
while (first < last&&arr[first] <= key) {
++first;
}
arr[last] = arr[first];
}
//跳出循环的条件first == last
arr[first] = key;
//以first为分界,左右两边各做排序
myQsort(arr, left, first);
myQsort(arr, first + 1, right);
}
int main(void) {
vector<int> arr = { 6,6,2,1,3,5,88,9,-1,0 };
myQsort(arr, 0, arr.size());
for (int i : arr) {
cout << i<<" " ;
}
return 0;
}