交换排序-经典的快速排序算法总结
时间复杂度,平均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