分别从初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”。先从 右往左找一个小于 6 的数,再从左往右找一个大于 6 的数,然后交换它们。这里可以用两个 变量 i 和 j,分别指向序列最左边和最右边。我们为这两个变量起个好听的名字“哨兵 “i ”和 “哨兵 ” j ”。刚开始的时候让哨兵 i 指向序列的最左边(即 i=1),指向数字 6。让哨兵 j 指向序 列的最右边(即 j=10),指向数字 8。
图示:
首先哨兵 j 开始出动。因为此处设置的基准数是最左边的数,所以需要让哨兵 j 先出动,
这一点非常重要(请自己想一想为什么)。哨兵 j 一步一步地向左挪动(即 j++),直到找到
一个小于 6 的数停下来。接下来哨兵 i 再一步一步向右挪动(即 i++),直到找到一个大于 6
的数停下来。最后哨兵 j 停在了数字 5 面前,哨兵 i 停在了数字 7 面前。
现在交换哨兵 i 和哨兵 j 所指向的元素的值。交换之后的序列如下。
6 1 2 5 9 3 4 7 10 8
然后我们剩下的也是这么操作,就可以实现我们所需要的了。只是需要注意一点:
到最后 i 和 j 相遇之后,即在本实例中的 3 的位置,因为我们要把基准数放在中间,所以最后要实现3和6的交换哦
那么根据这个思想,当以6位基准数完成一次排序之后,我们就可以在6的左边和右边分别找基准数,在两边分别进行快速排序,最后就可以完成对整个序列的排序。
整个过程图示:
快速排序之所以比较快,是因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候
设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全
部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样只能在相邻的数之间进
行交换,交换的距离就大得多了。因此总的比较和交换次数就少了,速度自然就提高了。当
然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和
冒泡排序是一样的,都是 O(N^2),它的平均时间复杂度为 O (NlogN)。
我们知道原理之后,我们来写一写实现代码吧:
#include <stdio.h>
int a[101],n;//定义全局变量,这两个变量需要在子函数中使用
void quicksort(int left,int right)
{
int i,j,t,temp;
if(left>right)
return;
temp=a[left]; //temp中存的就是基准数
i=left;
j=right;
while(i!=j)
{
//顺序很重要,要先从右往左找
while(a[j]>=temp && i<j)
j--;
//再从左往右找
while(a[i]<=temp && i<j)
i++;
//交换两个数在数组中的位置
if(i<j)//当哨兵i和哨兵j没有相遇时
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
//最终将基准数归位
a[left]=a[i];
a[i]=temp;
quicksort(left,i-1);//继续处理左边的,这里是一个递归的过程
quicksort(i+1,right);//继续处理右边的,这里是一个递归的过程
}
int main()
{
int i,j,t;
//读入数据
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
quicksort(1,n); //快速排序调用
//输出排序后的结果
for(i=1;i<=n;i++)
printf("%d ",a[i]);
getchar();getchar();
return 0;
}
这个是我们自己写快排的代码,其实在C和C++的库函数里面,有一个自带的快排函数qsort
这个函数的头文件:
#include <stdlib.h>
这个函数的书写格式,函数声明是这样:
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
声明里面的参数的分别是:
base -- 指向要排序的数组的第一个元素的指针。
nitems -- 由 base 指向的数组中元素的个数。
size -- 数组中每个元素的大小,以字节为单位。
compar -- 用来比较两个元素的函数
这几个参数里面,唯独最后一个参数不好理解。最后一个参数,是要传给他一个比较函数,比较函数是什么?就是比较两个数大小的函数;从哪里找这个函数?自己写!!
是的,最后那个参数其实就是一个自己写的比较函数。
为了方便大家理解,我们举个例子来使用一下。
#include <stdio.h> /* printf */
#include <stdlib.h> /* qsort */
int values[] = { 40, 10, 100, 90, 20, 25 };// 自定义的一个序列
int compare (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}// 这个就是我们自己写的比较函数,用于比较a,b大小.如果a小于b,则返回值为负数(< 0),也即a会排在b的前面。同理,若a大于b,则a会排在b的后面。所以,这里的qsort()为从小到大即升序排序。如果需要从小到大,那么就返回b-a即可
int main ()
{
int n;
qsort (values, 6, sizeof(int), compare);
//调用qsort函数 values 所需要排序的序列的首地址;6 代表序列有6个元素;sizeof(int)因为是个int数组,所以每个元素的大小是sizeof(int);最后compare就是我们自己的比较函数
for (n=0; n<6; n++)
printf ("%d ",values[n]);
return 0;
}
这个就是qsort函数的实例,不是很理解的可以评论区留言,然后自己多上手试试,这个函数还是比较好用的,这么使用不比我们自己写一个快速排序或者冒泡排序来的快?!
如果在这个基础上,运动动态分配是可以实现一个排序程序的(就是任一序列进行排序),大家也可以上手试一试,不是很难。
好滴,今天的分享到此结束,对了,大伙儿圣诞节快乐哦!!