您的位置:首页 > 其它

常用排序算法之快速排序

2016-04-24 23:25 246 查看
1.何为“快排”?

快速排序,即就是很快速,很便捷的一种排序嘛-!O(∩_∩)O~

但是,快速排序也并非一定是快速的。如果按照最糟糕的情况来看,它的时间复杂度几乎和冒泡排序是相同的0(n2)(是什么情况呢?)。但是,平均时间复杂度是0(NlogN)。

2.基本思想

快速排序是基于一种“二分”的思想。

它将在一组无序数中,寻找一个基准数,该数将原数组一分为二,左边的数组的数均小于该基准数,而右边的数组的数均大于该基准数。而该左,右两边的数组再依次递归进行上述操作,直至递归结束。

快速排序之所以被称为是冒泡排序的进化版,是因为冒泡排序每次比较的都是相邻的两个数,而快速排序只有在最坏的情况下才是这样。一般情况下,快排中的两数交换的距离要大得多!

3.算法模拟

原始数组

01234
32451
第一轮遍历

(1) 根据快排的思想,找到一个基准数,我们上面说过它可以是任意数,那么,我们姑且将数组中的第一个数作为基准数(其实不用姑且,因为地球银都这样),即将3作为基准数。

(2) 我们就开始伟大的征程了!先从右边开始j,寻找错误顺序的那个数(即比基准数小的数),然后,从左开始i,同样,寻找错误顺序的那个数(比基准数大的数)

01234
32451
(3) 根据上表,我们找到了a[2]=4,a[4]=1这两个站错位置的数。接着交换两个数的值(类似于冒泡排序)

01234
32154
(4) 还没有完,我们接下来继续找与基准数站错位置的数。黄天不负有心银,我们找到了5这个数。此时,我们要注意的是,5的左右两边我们之前已经将其他站错位置的数已经“排好序”,这说明,两军已经成功会师i==j!再将5这个数与基准数交换位置即可。

此时,第一轮遍历完毕!a[3]的顺序已经确定。

01234
52134
第二轮遍历

(1) 第一次遍历,我们将原始数组一分为二,left:a[0-2],right:a[4]

012
521
4
4
(2) 因为数据少,比较容易思考(好吧,是寡人太懒),所以right的数组中的值已经排好序了。

因此,我们来看left的数组。同理,将5作为基准数!

012
521
(3) 然后,先从右边开始(想想为什么每次都是从右开始)遍历,我们找到站错位置的a[2]=1,接着,开始从左开始遍历,啊哦~没找到。注意,a[2]=1的左右两边都已经被遍历过了(两军会师i==j)。那么,将1与基准数进行交换。

此时,第二轮遍历完毕。a[2]位置已经确定!

012
125
第三轮遍历

(1) 将上一轮的数组,以a[2]进行二分,很遗憾!只剩下左半边。left a[0-1]

01
12
(2) ok,先从右开始遍历,我们找到没有站错位的数,然后,就没有然后了..。因为,基准数的右边全都站位正确。a[0]=1位置已经确定!

第四轮遍历与第五轮遍历

a[1]=2,a[4]=4

这个不用说了,直接return 返回即可。

4.核心代码

(1) 寻找基准数a[1] a[0]作为临时变量,存储每次遍历后新数组的a[1]值

a[0] = a[left];//<span style="font-family: Arial, Helvetica, sans-serif;">3 3 1 2 5 4</span>
(2)从右往左开始遍历j--,找到站错位置的数a[j](比基准数a[0]小)

//从右往左遍历 ,寻找不满足条件的数 3 3 1 2 5 4
while(i<j){
if(a[0]>a[j]){
break;
}
j--;
}


(3) 从左往右开始遍历i++,找到站错位置的数a[i](比基准数a[0]大)

//从左往右遍历
while(i<j){
if(a[0]<a[i]){
break;
}
i++;
}


(4) 将会师点的数(i==j)a[i]或a[j]与基准数a[0]进行交换

a[left] = a[i];
a[i] = a[0];
(5)传送门调用

quickSort(left,i-1,a);//左半边调用
quickSort(i+1,right,a);//右半边调用


5.完整代码

#include <stdio.h>
#define N 100

void quickSort(int left,int right,int *a){
if(left>right){//即超过会师点
return;
}

int i = left;<span style="font-family: Arial, Helvetica, sans-serif;">//i,j存储当前的左右下标</span>
int j = right;

a[0] = a[left];
while(i<j){//每一轮循环
//从右往左遍历 ,寻找不满足条件的数 3 3 1 2 5 4 while(i<j){ if(a[0]>a[j]){ break; } j--; }
//从左往右遍历 while(i<j){ if(a[0]<a[i]){ break; } i++; }
if(i<j){//类似冒泡排序,交换站错位置的两个数
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
a[left] = a[i];//交换基准点与会师点的数
a[i] = a[0];

quickSort(left,i-1,a);
quickSort(i+1,right,a);

}

int main(void){

int n=5;
//scanf("%d",&n);
int a
={-1,3,1,2,5,4}; //a[0]=-1 相当于一个中转,存放基准数的临时变量

quickSort(1,n,a);

int i;

for(i=1;i<=n;i++){
printf("%-3d",a[i]);
}

return 0;

}


6.运算结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: