————————————————————————————————————————————————
你没有变强是因为你一直很舒服!
求知若饥,虚心若愚!
—————————————————————————————————————————————————
一 挖坑调整
快速排序,这也是在实际中最常用的一种排序算法,速度快,效率高。就像名字一样,快速排序是最优秀的一种排序算法。
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
方法的思想是:
1 先找一个基准值(理论上是可以随便找一个,但是做好选择第一个或者最后一个,方便理解,代码也简单)。
2对数组进行分区操作,小于基准的得数字都放到基准值的左边,大于等于基准值的数字都放到基准值的右边。
3此时基准值的位置已经确定,然后对两边的数字进行重复递归操作,使所有的数字都有序。
举例说明
2 2 4 9 3 6 7 15 取基准值是2,使用 i , j 两个指针分别从两边进行扫描,把比2小的元素和比2大的元素分开。首先比较2和5,5比2大,j左移一位
2 2 4 9 3 6 71 5 比较 2和1 ,2大于1,所以把1移动到2的位置。
2 1 4 9 3 6 7 1 5 然后从左边开始比较,比2大的,移动到 之前 1 的位置。因为4大于2,所以4移动到之前1的位置。
2 1 4 9 3 67 4 5 然后比较2和7, 2和6, 2和3, 2和9 都大于2,满足条件,所以第一轮比较结束。把2移动到最后的位置
最后的结果是 [1] 2 [ 9 3 6 7 4 5 ]
根据这个描述,我们先写一段代码实现如上的功能。
基本的编程思路是:我们先确定一个标志位(第一个元素),然后从右边开始依次和标志位比较。如果大于标志位则继续左移,如果小于标志位则移动到标志位,然后从右边开始比较,比标志位小的移动到右边那个位置。这块的理解可以参考挖坑+ 分治。(http://blog.csdn.net/morewindows/article/details/6684558)。
程序解读
在移动之前,先和标志位比较,首先要定位到比标志位小的数字处(确定比标志位小的 j 的值)while(j>i && a[j]>sig)j--; 这句话有两种退出的情况,第一就是 找到了 j 值使得 a[j] < sig 。还有一种就是 j = i 退出,所以我们接着就是 if(j>i)成立,则是第一种情况,
把a[j] 赋值给 a[i]的值(注意:这就是为什么要把第一个数字取做标志位。)。同时 i++ ,因为现在右边的坑空了,我们需要从左边开始找一个大于标志位的数字放到右边的坑里。i++ 就是确定 第 i 位置的数字已经小于标志位的值,不需要参与比较了。同理从左边开始寻找大于标志位的数字,然后移动过去。最后的状态就是 i 等于 j 。此时把标志位的值赋值给 a[i] 。完成分治的排序。
二 两边分治
如果细细的看“挖坑”的程序,形参 q 和 形参 n 就是 确定的进行挖坑比较的范围,如果你 赋值: q=1; n=5; 一共有10个待排序的数字,那么程序会把a[q]赋值给sig ,对1--5之内的数字进行挖坑而对于第0个 和 第6--9之间的数字是不会移动的。两边分治的代码就是对两边分别进行挖坑比较。代码如下:
#include<stdio.h>
void quickSort(int a[], int l, int r)
{
int sig=a[l];
int i,j;
i=l;
j=r;
if(l<r) //递归的退出条件
{
while(j>i)
{
while(j>i && a[j]>=sig)
j--;
if(j>i)
{
a[i]=a[j];
i++;
}
while(j>i && a[i]<sig)
i++;
if(j>i)
{
a[j]=a[i];
j--;
}
}
a[i]=sig;
quickSort(a,l,i-1);
quickSort(a,i+1,r);
}
}
int main()
{
int i;
int a[8]={6,15,9,7,1,8,2,10,};
quickSort(a,0,7);
for(i=0;i<8;i++)
printf("%d ",a[i]);
return 0;
}
三 快速排序的记忆
1 先挖坑,挖坑的时候需要定位所以定位代码就是 while 循环,定位到了然后如果比标志值大(或者小)就移动,挖坑完成然后就把标志位移动到最后一个位置。
2再分治,分治的时候就是循环递归的调用,注意递归的退出条件。