快排的效率很快,但是我们很少知道如何利用它进行多关键字排序,比如我想对一个数组a[i][0]进行的一个元素进行主关键字排序,又想对a[i][1]进行次关键字排序。那么接下来就是解决这个问题的方法。
学过数据结构的同学,应该知道快排的基本原理,就是将要排序的物品(不说成值,因为我们可能要排多维数组或者是结构体),就是每次将一个物品放到序列中最合适的位置,那么如何放,如果想要递增排序,就是前面的物品和后面的物品,谁大的放后面。所以通过这个原理就知道void qsort(void*, size_t, size_t, int*(const void*, const void*));这个函数传参数的时候为什么最后一个参数是一个函数了,真正进行排序交换的是qsort(),但是还需要一个比较两个物品的大小的操作,这个操作是需要用户自定义的,如果需要物品递增,那么这个比较函数cmp()返回的就是a>b[a-b]的true结果,这个时候排序的时候会把大的交换到后面。同理,要想物品递减,那么cmp()返回的就是a<b[b-a]了。
现在关键的问题来了。
如果排序仅仅是一个int a[N]的数组
int cmp(const void *a,const void *b)
{
return *(int *)a-*(int *)b;
}
//我来解释一下为什么会 return *(int *)a-*(int *)b;这个,因为我们传进到cmp()的参数是单个物体的地址,在这里我们传的是一个存储int值的一个int类型的地址,为了保持cmp()函数的可以让任何类型的数组进行比较大小,所以再传入到cmp()里面就会被转为不可变的const 的空void类型的地址,所以当我们在这个函数内部要比较大小时,又必须将这个地址转换成存储Int类型的地址,然后去取这个地址的值进行大小比较。所以(int *)a是将这个存储空类型void的地址强转换为存储int类型的地址,而只得到这个地址是比较不了大小的,这个时候就必须比较这个存储这个地址的内容了,获得地址内容只要在地址之前加上*号就可以了即*(int*)a这个的实际意义。
同理如果你要比较结构体数组,就需要在cmp内部把const void *a单个结构体成员的地址然后就是去结构体中需要比较大小的关键字了
int cmp( const void *a ,const void *b)
{
return (*(Node *)a).data > (*(Node *)b).data ? 1 : -1; //或者true,false
}
qsort(s,100,sizeof(s[0]),cmp);
根据这个结构体我们,同理可推出比较多维数组,这里我们用二维数组的例子,用二维数组的第二个值作为排序的关键字
int a[1000][2];qsort
(a,1000,
sizeof
(
int
)*2,comp);
intcomp(constvoid*a,constvoid*b)
{
return
((
int
*)a)[1]-((
int
*)b)[1];
}