快速排序在最坏情况下的时间复杂度为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
- #include
- #include
- 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函数内部的参考值。这样便可实现算法的随机化。