时间复杂度,平均O(nlogn),最坏O(n);
不稳定的算法
1、算法思想
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
(1) 分治法的基本思想
分治法的基本思想是:将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。
(2)快速排序的基本思想
设当前待排序的无序区为R[low..high],利用分治法可将快速排序的基本思想描述为:
①分解:
在R[low..high]中任选一个记录作为基准(Pivot),以此基准将当前无序区划分为左、右两个较小的子区间R[low..pivotpos-1)和R[pivotpos+1..high],并使左边子区间中所有记录的关键字均小于等于基准记录(不妨记为pivot)的关键字pivot.key,右边的子区间中所有记录的关键字均大于等于pivot.key,而基准记录pivot则位于正确的位置(pivotpos)上,它无须参加后续的排序。
注意:
划分的关键是要求出基准记录所在的位置pivotpos。划分的结果可以简单地表示为(注意pivot=R[pivotpos]):
R[low..pivotpos-1].keys≤R[pivotpos].key≤R[pivotpos+1..high].keys
其中low≤pivotpos≤high。
②求解:
通过递归调用快速排序对左、右子区间R[low..pivotpos-1]和R[pivotpos+1..high]快速排序。
③组合:
因为当"求解"步骤中的两个递归调用结束时,其左、右两个子区间已有序。对快速排序而言,"组合"步骤无须做什么,可看作是空操作。
1、如无序数组[3 2 4 1 5 9]
a),先把第一项[3]取出来,
用[3]依次与其余项进行比较,
如果比[3]小就放[3]前边,2 1 都比[3]小,所以全部放到[3]前边
如果比[3]大就放[3]后边,4 5 9比[3]大,放到[3]后边
一趟排完后变成下边这样:
排序前 3 2 4 1 5 9
排序后 2 1 3 4 5 9
b),对前半拉[2 1]继续进行快速排序
重复步骤a)【取第一项 2与其余项比较】后变成下边这样:
排序前 2 1
排序后 1 2
前半拉排序完成。
c),对后半拉[4 5 9]继续进行快速排序
重复步骤a)【取第一项 4与其余项比较】后变成下边这样:
排序前 4 5 9
排序后 4 5 9
d),对后半拉[5 9]继续进行快速排序
重复步骤a)【取第一项 5与其余项比较】后变成下边这样:
排序前 5 9
排序后 5 9
d在这个例子中可以忽略,但是当后面的数字较小时就得必不可少的循环继续下去。
前半拉排序完成。
总的排序也完成:
排序前:[3 2 4 1 5 9]
排序后:[1 2 3 4 5 9]
2、快速排序算法QuickSort
void QuickSort(SeqList R,int low,int high)
{ //对R[low..high]快速排序
int pivotpos; //划分后的基准记录的位置
if(low<high){//仅当区间长度大于1时才须排序
pivotpos=Partition(R,low,high); //对R[low..high]做划分
QuickSort(R,low,pivotpos-1); //对左区间递归排序
QuickSort(R,pivotpos+1,high); //对右区间递归排序
}
} //QuickSort
注意:
为排序整个文件,只须调用QuickSort(R,1,n)即可完成对R[l..n]的排序。
具体算法实现:
1: int partition(int R[], int low, int high)
2: {//对R[low..high]做划分
3: int pivot = R[low];
4: int tmp =0;
5: 6: // int i = low, j= high ;
7: // print(R+low,high-low+1);
8: 9: while(low < high)
10: { 11: while( low <high &&R[high] >= pivot)
12: --high ; 13: swap(R[low] ,R[high]); 14: 15: while (low < high && R[low] <= pivot )
16: ++low; 17: swap(R[low] ,R[high]); 18: 19: 20: } 21: 22: 23: //print(R+i,j-i+1);
24: 25: return high;
26: } 27: void quick_sort_z(int R[] ,int low ,int high)
28: { 29: int pivot_pos; //划分后的基准记录的位置
30: if(low<high){ //仅当区间长度大于1时才须排序
31: pivot_pos = partition(R ,low, high); //对R[low..high]做划分
32: // cout<<pivot_pos <<endl;
33: quick_sort_z(R, low, pivot_pos-1); //对左区间递归排序
34: quick_sort_z(R, pivot_pos+1, high);//对右区间递归排序
35: } 36: } 37: 38: void quick_sort(int R[], int low, int high)
39: { 40: quick_sort_z(R,low,high); 41: }
另一种partion算法实现:以最后一个元素作为基准
1: int partition_a(int data[],int lo,int hi)
2: { 3: int key=data[hi]; //以最后一个元素,data[hi]为主元
4: int i=lo-1;
5: for(int j=lo;j<hi;j++) ///注,j从p指向的是r-1,不是r。
6: { 7: if(data[j]<=key)
8: { 9: i=i+1; 10: swap(data[i],data[j]); 11: } 12: } 13: swap(data[i+1],data[hi]); 14: return i+1;
15: } 完整的源代码(VS2010编译):
1: // code-summary.cpp : 定义控制台应用程序的入口点。
2: 3: /**************************************************************************
4: * Copyright (c) 2013, All rights reserved.
5: * 文件名称 : code-summary.cpp
6: * 文件标识 :
7: * 摘 要 : 快速排序算法
8: *
9: * 当前版本 : Ver 1.0
10: * 作者 : 徐冬冬
11: * 完成日期 : 2013/05/10
12: *
13: * 取代版本 :
14: * 原作者 :
15: * 完成日期 :
16: * 开放版权 : GNU General Public License GPLv3
17: *************************************************************************/
18: #include "stdafx.h"
19: 20: #include <iostream>
21: #include <random>
22: #include <stdlib.h>
23: using namespace std;
24: 25: //快速排序
26: 27: void init(int a[], int len)
28: { 29: int i =0;
30: for( i=0; i<len ;i++)
31: { 32: a[i]= rand(); 33: } 34: return ;
35: } 36: void print(int *a, int len)
37: { 38: int i =0;
39: for( i=0; i<len; i++)
40: { 41: cout << a[i] <<'\t';
42: } 43: cout << endl; 44: return ;
45: } 46: void swap(int &a, int &b)
47: { 48: int tmp =a;
49: a = b; 50: b=tmp; 51: return ;
52: } 53: int partition(int R[], int low, int high)
54: {//对R[low..high]做划分
55: int pivot = R[low];
56: int tmp =0;
57: 58: // int i = low, j= high ;
59: // print(R+low,high-low+1);
60: 61: while(low < high)
62: { 63: while( low <high &&R[high] >= pivot)
64: --high ; 65: swap(R[low] ,R[high]); 66: 67: while (low < high && R[low] <= pivot )
68: ++low; 69: swap(R[low] ,R[high]); 70: 71: 72: } 73: 74: 75: //print(R+i,j-i+1);
76: 77: return high;
78: } 79: 80: int partition_a(int data[],int lo,int hi)
81: { 82: int key=data[hi]; //以最后一个元素,data[hi]为主元
83: int i=lo-1;
84: for(int j=lo;j<hi;j++) ///注,j从p指向的是r-1,不是r。
85: { 86: if(data[j]<=key)
87: { 88: i=i+1; 89: swap(data[i],data[j]); 90: } 91: } 92: swap(data[i+1],data[hi]); 93: return i+1;
94: } 95: 96: void quickSort(int R[] ,int low ,int high)
97: { 98: int pivot_pos; //划分后的基准记录的位置
99: if(low<high){ //仅当区间长度大于1时才须排序
100: pivot_pos = partition(R ,low, high); //对R[low..high]做划分
101: // cout<<pivot_pos <<endl;
102: quickSort(R, low, pivot_pos-1); //对左区间递归排序
103: quickSort(R, pivot_pos+1, high);//对右区间递归排序
104: } 105: } 106: 107: void quickSort_a(int R[] ,int low ,int high)
108: { 109: int pivot_pos; //划分后的基准记录的位置
110: if(low<high){ //仅当区间长度大于1时才须排序
111: pivot_pos = partition_a(R ,low, high); //对R[low..high]做划分
112: // cout<<pivot_pos <<endl;
113: quickSort_a(R, low, pivot_pos-1); //对左区间递归排序
114: quickSort_a(R, pivot_pos+1, high);//对右区间递归排序
115: } 116: } 117: void quick_sort(int R[], int low, int high)
118: { 119: quickSort(R,low,high); 120: } 121: 122: void quick_sort_a(int R[], int low, int high)
123: { 124: quickSort_a(R,low,high); 125: } 126: 127: 128: int _tmain(int argc, _TCHAR* argv[])
129: { 130: int *arr = new int[10];
131: init(arr, 10); 132: print(arr, 10); 133: quick_sort(arr,0,9); 134: print(arr, 10 ); 135: 136: init(arr, 10); 137: print(arr, 10); 138: quick_sort_a(arr,0,9); 139: print(arr, 10 ); 140: 141: system("pause");
142: return 0;
143: } 144:
参考资料:
http://student.zjzk.cn/course_ware/data_structure/web/paixu/paixu8.3.2.1.htm
http://www.cnblogs.com/kkun/archive/2011/11/23/2260270.html
http://blog.csdn.net/v_july_v/article/details/6262915