1.思想
- 快速排序采用的思想是分治思想。(Divide-And-Conquer)
2.基本分析
- 首先,假设所要排序的数字存储在数组S中,
- 然后对数组进行
分区移位操作
即基准左边区域的都是小于基准的,右边区域的都是大于基准的, - 然后将基准放在两区域分离的边界中心。
3.举个例子:2 4 9 3 6 7 1 5
- 首先用2当作基准,使用i j两个指针分别从两边进行扫描,把比2小的元素和比2大的元素 分开
首先比较2和5,5比2大,j左移
2基准 【2 】4 9 3 6 7 1 5
2基准【2】 4 9 3 6 7 1 5 比较2和1,1小于2,所以把1放在2的位置从左 边扫描
2基准1 4 9 3 6 7 【1】 5 比较2和4,4大于2,因此将4移动到后面
2 基准1 【4】9 3 6 7 4 5 比较2和7,2和6,2和3,2和9,全部大于2,满足条件,因此不变
经过第一轮的快速排序,元素变为下面的样子[1] 2 [4 9 3 6 7 5]
将两区域的进行排序,左边一个元素,有序。右边进行快速排序,递归进行。
void quicksort(int a[], int left, int right){
if(left < right){
int key = a[left];
int low = left;
int high = right;
while(low < high){
while(low < high && a[high] > key){
high--;
}
a[low] = a[high]; //a[high]已经空下来
while(low < high && a[low] < key){
low++;
}
a[high] = a[low]; //a[low]已经空下来
}
a[low] = key;//中间数值省去返回值
quicksort(a,left,low-1);
quicksort(a,low+1,right);
}
}
4.总结
快速排序的时间主要耗费在划分操作上,对长度为k的区间进行划分,共需k-1次关键字的比较。
最坏情况是每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。时间复杂度为O(n*n)
在最好情况下,每次划分所取的基准都是当前无序区的”中值”记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。总的关键字比较次数:O(nlgn)
尽管快速排序的最坏时间为O(n2),但就平均性能而言,它是基于关键字比较的内部排序算法中速度最快者,快速排序亦因此而得名。它的平均时间复杂度为O(nlgn)。
- 上述算法没有返回值发现有点问题,下面是一个有返回值的,更能体现分治法。
void QuickSort(ElemType a[],int low, int high){
if(low < high){ //递归跳出条件
// Partition()就是划分操作,将表划分为两个子表
int pivotpos=Partiton(a,low,high);
Quicksort(a,pivotpos+1,high);
}
int Partiton(EleType a[],int low ,int high){
ElemType piot = a[low] ; //将当前表的第一个元素设为中枢
while(low < high){
while( low < high&&a[high] >= pivot )
--high;
a[low] = a[high]; //比中枢小的移到左边
while(low < high&&a[low] <= pivot)
++low;
a[high] = a[low]; //比中枢大的移到右边
}
a[low] = pivot;
return low;中枢的位置
}