快速排序是一种高效的非稳定排序,它的基本思路是分支法,在一个序列a[]中找到一个数a[mid],然后将序列a[]分为3部分a[start]---a[i-1],a[i],a[i+1]---a[end],第一部分的序列中,所有的数都小于a[i],第二部分的序列中,所有的数都大于a[i]。然后递归的对前后两部分进行处理,直到序列完成排序。
那么快速排序的关键步骤就是对序列进行重排。有两种思路1)单向扫描。2)双向扫描。
单向扫描:根据算法导论第二版他的算法流程为:
PARTITION(A, p, r) 1 x ← A[r] //以最后一个元素,A[r]为主元 2 i ← p - 1 3 for j ← p to r - 1 //注,j从p指向的是r-1,不是r。 4 do if A[j] ≤ x 5 then i ← i + 1 6 exchange A[i] <-> A[j] 7 exchange A[i + 1] <-> A[r] //最后,交换主元 8 return i + 1
可以看到,以序列的最后一个元素为基准元素,从序列头部开始扫描,如果发现a[i]小于基准元素,将他交换到序列前部(注意前部指针交换一次就加1)
双向扫描:
OARE-PARTITION(A, p, r) 1 x ← A[p] 2 i ← p - 1 3 j ← r + 1 4 while TRUE 5 do repeat j ← j - 1 6 until A[j] ≤ x 7 repeat i ← i + 1 8 until A[i] ≥ x 9 if i < j 10 then exchange A[i] <-> A[j] 11 else return j
可以看到,扫秒从2头开始,如果发现a[i]>mid&&a[j]<mid将两者交换,注意基准元素为a[p],最后返回的是j
最后给出具体代码,附带了随机化版本:
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<time.h> using namespace std; void swap(int *src,int a,int b) { int temp=src[a]; src[a]=src[b]; src[b]=temp; } int partition(int* src,int start,int end) { int result; int i=start; int j=end; int mid=src[start]; end=end+1; while(1) { while(src[++start]<mid&&start<j); while(src[--end]>mid); if(start>=end) break; swap(src,start,end); } swap(src,i,end); return end; } int partition_single(int*src,int start,int end) { int mid=src[end]; int i=start-1; for(int j=start;j<end;j++) { if(src[j]<=mid) { ++i; swap(src,i,j); } } swap(src,i+1,end); return i+1; } int randomPartition(int*src,int start,int end) { srand(time(NULL)); int n=rand()%(end-start+1); int r=start+n; swap(src,start,r); return partition(src,start,end); //return partition_single(src,start,end); } void q_sort(int *src,int start,int end) { if(start>=end) return; //int result=partition(src,start,end); //int result=partition_single(src,start,end); int result=randomPartition(src,start,end); q_sort(src,start,result-1); q_sort(src,result+1,end); } int main() { int src[16]={16,11,15,9,10,13,14,8,2,1,5,12,6,3,7,4}; q_sort(src,0,15); for(int i=0;i<16;i++) cout<<src[i]<<" "; cout<<endl; return 0; }