qsort函数
qsort函数是一种可以对任意类型的数据进行排序的函数,它的定义在<stdlib.h>头文件中,它的函数原型如下:
void qsort(void *base, size_t num, size_t size, int (*compar)(const void*, const void *));
这个函数一共有四个参数,它们分别是:
-
1.
base:指向待排序数组的第一个元素的指针。 -
2.
num:数组中元素的个数。可以使用sizeof(arr)/sizeof(arr[0])来求出元素个数。
-
3.
size:每个元素的大小(以字节为单位)。可以使用sizeof(类型)求出,例如sizeof(int)。
-
compar:指向比较函数的指针,该函数用于确定两个元素的顺序。
qsort的使用
//排序整型数组
#include <stdio.h>
#include <stdlib.h>
int cmp(void* a, void* b)
{
return (*(int*)a - *(int*)b);
}
//void qsort(void *base,
// size_t num,
// size_t size,
// int(*cmp)(const void*,const void*))
int main()
{
int arr[] = { 9,7,6,5,8,4,2,3,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
int size = sizeof(int);
int i = 0;
//打印原数组
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
qsort(arr, sz, size, cmp);
//打印排序后的数组
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
qsort中的compar函数是需要自己编写的,它的作用是比较相邻两个元素的大小 ,它的返回值是int类型,有三种情况:
- a>b -> 大于0
- a<b - > 小于0
- a=b -> 等于0
输出结果为:(上方为原数组)

(qsort默认是升序的,如果想降序可以将a,b调换一下)
//排序结构体数组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Stu
{
char name[20];
int age;
};
int cmp(const void* a, const void* b)
{
return strcmp((*(struct Stu*)a).name, (*(struct Stu*)b).name);
//这里排序Stu中的name字符串
}
int main()
{
struct Stu arr[] = {{"zhangsan",20},{"lisi",30},{"wangwu",40} };
int sz = sizeof(arr) / sizeof(arr[0]);
int size = sizeof(arr[0]);
int i = 0;
qsort(arr, sz, size, cmp);
for (i = 0; i < sz; i++)
{
printf("%s ", arr[i].name);
}
return 0;
}
字符串的比较是通过两个字符串中每位字符的ANSIC码值来比较的,例如”zhangsa“和“lisi”,"z"的码值比"l"大,所以“zhangsa”大。
结构体中调用其中的类型的方法有两种,一是**(结构体).(类型名)**,如(struct Stu a).name,另一种是(结构体指针)->(类型名),如((struct Stu*)a)->name。
冒泡排序对qsort的模拟实现
冒泡排序之前我们已经说过,它是一种将数据升序排列的方法,它的代码如下:
#include <stdio.h>
void bubble_sort(int arr[], int sz)
{
int i = 0;
int flag = 1;//假如初始时便是正序
for (i = 0; i < sz - 1; i++)//趟数
{
int j = 0;
for (j = 0; j<sz-i-1;j++ )
{
if (arr[j] > arr[j + 1])
{
flag = 0;//需要交换,就不是正序
int tmp = 0;
tmp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = tmp;
}
if (flag == 1)
{
break;//flag为1,即剩下的本就是正序,不需要再交换
}
}
}
}
int main()
{
int arr[] = { 3,1,7,4,2,6,8,9,0,5 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
但上述代码只能排列整型,我们如何使它能像qsort函数一样可以排序任意类型的数据呢?
我们来分析一下:
void bubble_sort(int arr[], int sz)
对于int arr[],它的int类型应该变成void类型以便于接受任意类型的数据,仿照qsort的函数原型,我们将其变为:
void bubble_sort(void*base, size_t sz,size_t size,int(*cmp)(const void*e1,const void*e2))
那么如何向cmp函数传输某一个元素和下一个元素呢?我们可以这样:
我们之前传输了第一个元素的指针base和类型宽度size

我们可以将一个元素以字节为单位进行分割(以int为例)

如果将base强制转换为char *类型,根据char*的特点,char*+1移动一个字节,既然我们已经知道了类型长度size,那么(char*)base + 1*size便指向第二个元素arr[1],
(char*)base + j*size和(char*)base +(j+1)*size便指向arr[j]和arr[j+1]。

这样我们实现了任意类型的传输
总代码如下:
#include <stdio.h>
#include <string.h>
struct Stu
{
char name[20];
int age;
};
int cmp_int(void*base,size_t sz,size_t size,int j)
{
return (*((char*)base + j * size)) - (*((char*)base + (j + 1) * size));
}
int cmp_struct(void* base, size_t sz, size_t size, int j)
{
return strcmp(((struct Stu*)((char*)base + j * size))->name, ((struct Stu*)((char*)base+ (j + 1) * size))->name);
}
void exchange(int(*cmp)(void* base, size_t sz, size_t size, int j),void* base, size_t sz, size_t size, int j)//交换
{
if (cmp(base, sz, size, j) > 0&&size == sizeof(int))
{
int tmp = 0;
tmp = (*((char*)base + (j + 1) * size));
(*((char*)base + (j + 1) * size)) = (*((char*)base + j * size)) ;
(*((char*)base + j * size)) = tmp;
}
else if(cmp(base, sz, size, j) > 0 && size == sizeof(struct Stu))
{
struct Stu tmp = *((struct Stu*)((char*)base + (j + 1) * size));
*((struct Stu*)((char*)base + (j + 1) * size)) = *((struct Stu*)((char*)base + j * size));
*((struct Stu*)((char*)base + j * size)) = tmp;
}
}
void bubble_sort(void* base, size_t sz, size_t size)
{
int i = 0;
int flag = 1;//假如初始时便是正序
for (i = 0; i < sz - 1; i++)//趟数
{
int j = 0;
for (j = 0; j < sz - i - 1; j++)
{
//判断要交换数据的类型
if (size == sizeof(int))
{
//交换
exchange(cmp_int, base,sz, size, j);
}
else if(size == sizeof(struct Stu))
{
exchange(cmp_struct, base,sz, size, j);
}
flag = 0;
}
if (flag == 1)
{
break;//flag为1,即剩下的本就是正序,不需要再交换
}
}
}
void Print_int(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s ", arr[i]);
}
}
void Print_Stu_name(struct Stu arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s ", arr[i].name);
}
}
int main()
{
struct Stu arr[] = {{"zhangsa",18},{"lisi",19},{"wanwu",20}};
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz,sizeof(arr[0]) );
if (sizeof(arr[0]) == sizeof(int))
{
Print_int(arr, sz);
}
else if (sizeof(arr[0]) == sizeof(struct Stu))
{
Print_Stu_name(arr, sz);
}
return 0;
}

997

被折叠的 条评论
为什么被折叠?



