快速排序在最坏情况下的时间复杂度为O(n2),但其期望时间复杂度是O(nlogn),且其中隐含的常数因子很小,固快速排序通常是实际排序应用中最好的选择。
快速排序的思路如下:
1、从A[p,r]中选出一个q,使得A[p,q-1]中的元素均小于A[q],A[q+1,r]中的元素均大于A[q];
2、对A[p,q-1]及A[q+1,r]进行快速排序,如此递归。
关键点在于如何选取其中的q,将该函数命名为partition(),其代码如下:
int partition(vector<int>& A, int p, int r)
{
int i = p - 1;
int x = A[r];
for (int j = p; j < r; ++j)
{
if (A[j] <= x)
{
i = i + 1;
int temp = A[j];
A[j] = A[i];
A[i] = temp;
}
}
int temp = A[i + 1];
A[i + 1] = A[r];
A[r] = temp;
return i + 1;
}
记住以下几点前提:
1、默认取A[r]为参照值,即为最后确定的A[q](最后将r位置的元素移动到q处);
2、i元素是起到了分界线的作用,在i左边是比A[r]小的元素,在右边则反之。
对A中的元素从p遍历到r-1,一旦遇到了比A[r]小的数,就需要将i往右移一格(因为i最初在p-1的位置),随后将这个比A[r]小的数与A[i]交换,这样就可以保证i元素的功能正常。当前期一直是比A[r]小的数时,就相当于同一个数与自身交换,所以i元素的作用也是正常的。当遇到比A[r]大的数时,跳过循环,进行下一个遍历。
实现代码如下:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int partition(vector<int>& A, int p, int r)
{
int i = p - 1;
int x = A[r];
for (int j = p; j < r; ++j)
{
if (A[j] <= x)
{
i = i + 1;
int temp = A[j];
A[j] = A[i];
A[i] = temp;
}
}
int temp = A[i + 1];
A[i + 1] = A[r];
A[r] = temp;
return i + 1;
}
void quicksort(vector<int> &A,int p,int r)
{
if (p < r)
{
int q;
q = partition(A, p, r);
quicksort(A, p, q - 1);
quicksort(A, q + 1, r);
}
}
int main()
{
int num;
cout << "输入子数组的元素数目" << endl;
cin >> num;
vector<int> vector_test(num);
cout << "依次输入子数组的各元素" << endl;
for (int i = 0; i < num; ++i)
{
cin >> vector_test[i];
}
cout << "以下是快速排序算法后的结果" << endl;
quicksort(vector_test,0,num-1);
for (int i = 0; i < vector_test.size(); ++i) { cout << vector_test[i] << endl; }
return 0;
}
前面提到,对于最坏情况,快速排序的时间复杂度跟插入排序一样。为了避免这种情况的发生,使快速排序的时间复杂度尽量接近期望值,需要引入随机化的功能。
随机化体现在partition函数中选取的A[r]。因为在实际应用中,所有数据的排列并不是等概率的,很可能A[r]本身的选取就是最坏的情况。因此需要选用随机化函数,生成一个在p-r之间的随机数,将这个随机数所处位置的值与A[r]进行交换,将新的A[r]作为partition函数内部的参考值。这样便可实现算法的随机化。