首先我们先写一个简单的整型数组冒泡排序
~~~c
#include
#include
Maopao(int arr[], int sz)
{
int i = 0;
//确定躺数
for (i =sz-1; i>0 ; i--) //每走一趟就会排好一个数,依次减少
{
int j = 0;
for (j = 0; j < i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
Print(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
printf("%d ", arr[i]);
}
int main()
{
int arr[] = { 1, 3, 7, 9, 2, 4, 5, 6, 8, 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
Maopao(arr, sz);
Print(arr,sz);
system("pause");
return 0;
}
~~~
显然对于这种冒泡排序只能针对整型数组,而对于浮点型数组和结构体数组等就很无力,所以对除整型数组外的其他数组进行排序就要用到库函数qsort
接下来我们看看如何使用库函数qsort
调用qsort需要头文件 #include
qsort的具体使用如下:
~~~c
#include
#include
int main()
{
int arr[10] = { 9, 8, 7, 3, 1, 2, 6, 4, 5, 0};
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int); //第一个参数:待排序数组的首元素地址
//第二个参数:待排序数组的元素个数
//第三个参数:待排序数组的每个元素的大小
//第四个参数:是(函数名)函数地址,这个函数使用者自己实现
//函数的两个参数是:待比较两个元素的地址
//cmp函数的返回值要为整型(>0,<0,或者=0的数),作为qsort的回调函数进行判断是否将两个元素交换
Print1(arr,sz); //打印函数
system("pause");
return 0;
}
~~~
例子中 cmp_int函数的实现如下:
int cmp_int(const void* e1, const void* e2) //void* 可接受任何类型的地址
{
return ((int)(*(int*)e1 - *(int*)e2));
//因为例子中为整型数组,所以要将两个元素
//的地址强制转换为整型,解引用后做差,将
//结果返回,用于比较两个元素的大小
}
若是浮点型数组则可改为:
int cmp_float(const void* e1, const void* e2)
{
return ((int)(*(float*)e1 - *(float*)e2));
}
若是结构体数组则可改为:
int com_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
这样我们就可实现对任意数组元素进行冒泡排序!
紧接着我们看一下qsort函数的是如何巧妙构建的!!!
void Swap(char* buf1, char* buf2, int width)
{
char* tmp=NULL;
int i = 0;
for (i = 0; i < width; i++) //width为数组一个元素的大小
{
char tmp = *buf1; //char*所接受的地址为元素的地址,也是元素第一个字节
的地址 ,但解引用操作只能作用于一个字节
*buf1 = *buf2;
*buf2 = tmp; //交换一个字节上的内容
buf1++; //通过循环实现两个要进行交换的元素的每个字节的内容都能进行交换,以达到两
个元素交换的目的
buf2++;
}
}
void my_qsort(void* base, int sz, int width, int(*cmp)(void* e1, void* e2))
//通过函数指针接受cmp函数的地址
int(*cmp)(void* e1, void* e2)
{
int i = 0;
//躺数
for (i = sz - 1; i > 0; i--)
{
int j = 0;
//每一趟两个元素的比较
for (j = 0; j < i; j++)
{
if (cmp((char*)base + width*j, (char*)(base)+width*(j+1))>0)
//将首元素的地址强制转换为char*类型,通过数组元素的大小可以方便确定出第二个元素的
地址,依次循环确定出每个元素的地址
//若经过cmp函数判断第一个元素大于第二个元素,则进入交换函数
{
Swap((char*)base + width*j, (char*)(base)+width*(j + 1),width);
//将两个元素的地址传入交换函数
}
}
}
}
我们调用看一下:
#include
#include
#include
struct Stu
{
char name[20];
int age;
};
int com_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_age(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void Swap(char* buf1, char* buf2, int width) //char*所接受的地址为元素的地址,也是元素第一个
字节的地址 ,但解引用操作只能作用于一个字节
{
char* tmp = NULL;
int i = 0;
for (i = 0; i < width; i++) //width为数组一个元素的大小
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp; //交换一个字节上的内容
buf1++; //通过循环实现两个要进行交换的元素的每个字节的内容都能进行交换,以达到两个元素交换的目的
buf2++;
}
}
void my_qsort(void* base, int sz, int width, int(*cmp)(void* e1, void* e2)) //通过函数指针int(*cmp)(void* e1, void* e2)接受cmp函数的地址
{
int i = 0;
//躺数
for (i = sz - 1; i > 0; i--)
{
int j = 0;
//每一趟两个元素的比较
for (j = 0; j < i; j++)
{
if (cmp((char*)base + width*j, (char*)(base)+width*(j + 1))>0)
//将首元素的地址强制转换为char*类型,通过数组元素的大小可以方便确定出第二个元素的地址,依次循环确定出每个元素的地址
//若经过cmp函数判断第一个元素大于第二个元素,则进入交换函数
{
Swap((char*)base + width*j, (char*)(base)+width*(j + 1), width); //将两个元素的地址传入交换函数
}
}
}
}
int main()
{
struct Stu s[] = { { "张三", 18 }, { "李四", 38 }, { "王五", 26 } };
int sz = sizeof(s) / sizeof(s[0]);
my_qsort(s, sz, sizeof(s[0]), cmp_age);
system("pasue");
return 0;
}
看一下调试的结果
由调试的结果知,我们设计的my_qsort是成功的!!!