C语言库里有qsort()函数来实现快速排序:
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
这是它的函数声明。
我们也能知道这个函数不仅可以对数字进行排序,也可以对各种数据类型进行排序,只是你需要自己写一个比较函数,即compare(const void *elem1, const void *elem2 );
鉴于此,我们可以对我们自己写的冒泡排序进行改造(当然你想改造选择排序也是可以的,我只是用冒泡做示范,偷偷说我有点喜欢冒泡,无理由哈哈),把它变成一个也可以排序任意类型数据的算法。
一下是代码汇总:(我会在下面分段介绍)
#include <stdio.h>
int cmp_int(const void* e1, const void* e2)
{
if (*(int*)e1 > *(int*)e2)
return 1;
else if (*(int*)e1 == *(int*)e2)
return 0;
else
return -1;
}
void swap(char* e1, char* e2,unsigned int width)
{
int i;
char temp;
for (i = 0; i < width; ++i)
{
temp = *e1;
*e1 = *e2;
*e2 = temp;
++e1;
++e2;
}
}
void sort(void* base, unsigned int num, unsigned int width, int(*cmp)(const void* e1, const void* e2))
{
int i, j;
int flag;
for (i = 0; i < num - 1; ++i)
{
flag = 1;
for (j = 0; j < num - 1 - i; ++j)
{
if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
{
swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
flag = 0;
}
}
if (flag) break;
}
}
int main()
{
int arr[10] = { 1,4,2,3,6,7,9,5,8,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
sort(arr, sz, sizeof(int), cmp_int);
for (int i = 0; i < 10; ++i)
{
printf("%d ", arr[i]);
}
return 0;
}
我定义了优化的冒泡排序函数sort()
参数和库函数中的qsort()一样:
第一个void *base是数组的起始地址
第二个unsigned int num是待排序数据元素的个数
第三个unsigned int width是待排序的数据元素的大小(单位byte)
最后一个int(*cmp)(const void* e1, const void* e2)是函数指针,用来比较大小
先看函数cmp_int(),它是用来比较数据大小的,他的返回值如下:
返回值 | 规则 |
<0 | e1小于e2 |
=0 | e1等于e2 |
>0 | e1大于e2 |
再看swap(),这是用来交换数据的,它的实现原理很简单,就是把两个数据每个字节都交换,那不就相当于交换了两个数据了吗?
至于为什么参数和函数内部用char *和char类型来操作数据,在下面sort()函数里面解释
接下来是重要部分,就是sort()函数
基本框架还是冒泡排序(说人话就是两个嵌套的for循环)
其中的变量flag的作用我解释一下:在冒泡排序中,我们可能会遇到数据已经排序好的情况,这时候就不用再继续遍历,所以我们用flag来判断,每次进行最外层循环都将flag设为1,然后进入内层循环,当发生数据交换时设为0,结束内层循环后判断flag的值,如果为1说明数据已经有序,不用再进行外层循环,否则继续。(由此可知外循环至少进行1次)
再if中调用cmp函数,也就是外部传进来的cmp_int()函数,来判断数据的大小关系,先看参数base,它的类型是void *(泛类型指针),所以我们无法对它直接解引用和加减法,先强制类型转换为char *(因为char *一次就访问一个字节)然后加上移动量(j*width)获得目标地址,再传给cmp函数,同理再cmp函数里面也要先强制类型转换为char *再解引用
所以现在知道为什么cmp_int()的参数和函数内部要用char *和char类型来操作数据了吧?
然后结束!
没了!!