快排
1.为什么要用快排?
因为一旦遇到大量的数据,快排相对别的排序方法来说,用时更短,而不用其他的排序方法,循环好多次。
例如冒泡排序法,我们知道需要两个循环,一个是控制交换的趟数,一个是控制冒泡比较的数量,例如下面:
//只用来说明上述问题,代码并不全
for(i=0 ; i < n ; i++)
{
for(j=0; j<n-i-1 ; j++)
{
..................
}
}
(可能有的人看这个很不习惯,因为有人习惯 i = 1 开始)从上面可以看出,有两重循环,这个就涉及到时间复杂读的概念了。
我们都知道,冒泡排序的时间复杂度为O(N^2)
而这个快排的平均时间复杂度为O(Nlogn)
说一说我刚开始接触快排吧,一直只知道它的名字,却不会打,也不知道快在哪里?有一天突然在一本书上看到了,于是就想要学会它,或许这就是缘分吧哈哈哈!
接下来就说说刚开始打这个快排的时候可能会遇到的问题。(没关系,你们要走的坑坑哇哇我都替你们已经趟过去了)
//快排函数
void quicksort(int left,int right) //首先定义两端的标兵
{
int temp,flag,i,j;
if(left>right) //相等时候用递归,并不是结束递归
return ;
i=left;
j=right; //i,j标兵
flag=a[left];
while(i != j)
{
while(a[j]>flag && i<j) //没有等于号,
j--;
while(a[i]<flag && i<j)
i++;
if(i<j)
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
a[left]=a[i];
a[i]=flag;
//开始子序列的排序,再次调用该函数进行排序
quicksort(left,i-1);
quicksort(i+1,right); // 调用递归
return ;
}
来说说这段花里胡梢的代码吧!
1.其实无非就是明白三点,找基准数,让基准数左边的数都比基准数小,右边的数都比基准数大,然后让基准数归位。
2.基准数还是要定一个好找一点的,所以在这里就将最左边的数规定为基准数。
3.然后将这些数字的最左端定为坐标兵,最又边定义为右标兵,先让右边的标兵一直向左移,找到比基准数小的,就让他停下来。
4.然后左标兵就位,开始向右走,直到找到比基准数大的,则停下。
5.如果他们没有相遇,则将标兵所指的数交换,继续这样循环。
6.那么什么时候循环结束呢?那肯定是他们相遇的时候了,这时这些数被分为两组,那我们就分而治之,继续将左边的进行上述的处理,再将右边的进行上述的处理,直到全部有序。
7.以上就是快排的基本步骤。
其实不难看出,快排用到了递归的思想,递归就一定要考虑到递归结束的条件,而在快排中,它的结束条件就是左标兵跑到了右标兵右边,注意,相等的时候不能结束递归,因为相等的点就是我们要分而治之的点。