目录
qsort函数简介
qsort()函数,快速排序函数,可以实现任意类型数据的排序 头文件 #include<stdlib.h>
参数说明:
void qsort(void* base,size_t num,size_t width,int(*cmp)(const void* e1,const void* e2));
1.void* base接收目标数组的起始位置,因为是任意类型数据排序,所以使用void*指针接收地址
2.size_t num 目标数组的元素个数
3.size_t width 数组每个元素所占字节的大小,以字节为单位
4.int(*cmp)(const void* e1,const void* e2) -函数指针,传参数时只需要传递函数名
cmp()比较函数要求qsort()函数的使用者自定义比较函数,e1,e2待比较的俩个元素的地址;
返回值为int
e1指向的待比较元素<e2指向的待比较的元素 返回小于0的数字;
e1指向的待比较元素等于e2指向的待比较的元素 返回0;
e1指向的待比较元素>e2指向的待比较的元素 返回大于0的数字;
qsort函数的使用
整型数组排序(升序)
如果数组想变成降序排列,对于方法一只需改变返回值即可;
e1指向的待比较元素<e2指向的待比较的元素 返回大于0的数字;
e1指向的待比较元素等于e2指向的待比较的元素 返回0;
e1指向的待比较元素>e2指向的待比较的元素 返回小于0的数字;若数组想变成降序排列,对于方法二只需要写成e2-e1即可;
cmp_int 函数实现方法一
int cmp_int(const void*e1, const void*e2)
{
//void*无确切类型指针,不可进行解引用操作;
//比较整型数据,先强制类型转换为int*,再进行解引用操作
if (*(int*)e1 > *(int*)e2)
{
return 1;
}
else if (*(int*)e1 == *(int*)e2)
{
return 0;
}
else
return -1;
}
cmp_int 函数实现方法二
int cmp_int(const void*e1, const void*e2)
{
return *(int*)e1 - *(int*)e2;
}
代码总览(cmp函数采用方法二实现)
int cmp_int(const void*e1, const void*e2)
{
return *(int*)e1 - *(int*)e2;
}
void print(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr, sz);
}
字符数组排序(升序)
浅谈sizeof()操作符和 strlen()函数:
sizeof 首先是一个操作符,返回值的类型为size_t=unsigned int
sizeof()计算的是对象所占内存的大小,单位为字节,并不在乎内存中存放什么元素,只在乎对象所占内存的大小,对于字符串而言,sizeof计算字符数组元素个数包含 '\0';
strlen()是一个库函数,头文件 # include <string.h>
参数为指针,返回值为size_t, strlen()函数是求字符串长度,从给定的地址向后访问字符,
统 计 '\0' 之前出现的字符个数;
cmp_char实现方法1
int cmp_char(const void*e1, const void*e2)
{
if (*(char*)e1 > *(char*)e2)
{
return 1;
}
else if (*(char*)e1 == *(char*)e2)
{
return 0;
}
else
return -1;
}
cmp_char实现方法2
int cmp_char(const void*e1, const void*e2)
{
return *(char*)e1 - *(char*)e2;
}
代码总览(cmp函数采用方法二实现)
int cmp_char(const void*e1, const void*e2)
{
return *(char*)e1 - *(char*)e2;
}
int main()
{
char arr[] = "fedcba";
int sz = sizeof(arr) / sizeof(arr[0]);
int len=strlen(arr);
qsort(arr, sz - 1, sizeof(arr[0]), cmp_char);
printf("%s\n", arr);
qsort(arr, len, sizeof(arr[0]), cmp_char);
printf("%s\n", arr);
return 0;
}
运行结果:
浮点型数组排序(升序)
注意:比较函数返回类型为int,最后相减的值要强制类型转换为int,cmp_float实现方法2容易导致错误
cmp_float实现方法1
int cmp_float(const void* e1, const void*e2)
{
if (*(float*)e1 > *(float*)e2)
{
return 1;
}
else if (*(float*)e1 == *(float*)e2)
{
return 0;
}
else
return -1;
}
cmp_float实现方法2
int cmp_float(const void* e1, const void*e2)
{
//返回类型为int,所求结果要强制类型转换为int
//4.4-4.3=0.1强制类型转化后结果为0,导致错误;
return (int)(*(float*)e1 - *(float*)e2);
}
代码总览(cmp函数采用方法1实现)
int cmp_float(const void* e1, const void*e2)
{
if (*(float*)e1 > *(float*)e2)
{
return 1;
}
else if (*(float*)e1 == *(float*)e2)
{
return 0;
}
else
return -1;
}
void print(float arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%f ", arr[i]);
}
}
int main()
{
float arr[] = { 1.2f, 2.3f, 5.4f, 4.4f, 4.3f };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_float);
print(arr, sz);
return 0;
}
运行结果:
代码总览(cmp函数采用方法2实现)
int cmp_float(const void* e1, const void*e2)
{
//返回类型为int,所求结果要强制类型转换为int
//4.4-4.3=0.1强制类型转化后结果为0,导致错误;
return (int)(*(float*)e1 - *(float*)e2);
}
void print(float arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%f ", arr[i]);
}
}
int main()
{
float arr[] = { 1.2f, 2.3f, 5.4f, 4.4f, 4.3f };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_float);
print(arr, sz);
return 0;
}
运行结果:
结构体数组排序
数据无非三种类型,即字符 浮点型 整型,而对于整型,浮点型的比较只需要 > < >= <= ==这些关系运算即可比较,但是如何比较字符呢?
strcmp()函数 字符串比较函数,头文件 # include <string.h>
参数解读:
1. strcmp()函数根据ASCII编码开始比较每个字符串的第一个字符,如果彼此相等,继续比较下一对字符对应的ASCII码值,直到字符不同或达到终止字符 '\0';
2. 函数返回值为int类型;
3. 返回值为大于0的数字,表示第一个字符串大于第二个字符串;
返回值为0,表示俩个字符串相等;
返回值为小于0的数字,表示第一个字符串小于第二个字符串;
//结构体声明
struct stu
{
char name[20];
int age;
double score;
};
//cmp函数实现
int cmp_stu_by_name(const void* e1, const void* e2)
{
//比较姓名-实际比较字符串-strcmp()函数
//int strcmp(const char*str1,const char* str2)
//strcmp里面的参数为指针,结构体指针传参
return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
int main()
{
//结构体数组创建和初始化
struct stu arr[3] = { { "zhangsan", 20, 60 }, { "lisi", 30, 55.5 }, { "wangwu", 25, 85.6 } };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(struct stu), cmp_stu_by_name);
printf("%s %d %f\n", arr[0].name, arr[0].age, arr[0].score);
printf("%s %d %f\n", arr[1].name, arr[1].age, arr[1].score);
printf("%s %d %f\n", arr[2].name, arr[2].age, arr[2].score);
return 0;
}
运行结果:
qsort()函数的模拟实现
qsort()函数的几点思考:
1. 使用qsort要实现任意类型数据的排序,因此qsort的第一个参数void* base,将第一个参数类 型设置为void*是因为void*可以接收任意类型的数据,排序一组数据,将这组数据所在内存空间的起始位置作为参数;
2. base为void*,这个数组的数据类型无从得知,需要知道确切的元素个数 size_t num;
3. base为void*, 但是每个元素的大小无法得知 size_t width;
4.冒泡排序中,一旦元素个数确定,冒泡排序的趟数和要比较元素的对数也将唯一确定;
唯一的差异是要排序任意类型的数据,里面的比较方法不同;
将比较方法提取出来,例如:按照整型数据比较,函数最后一个参数传一个比较整型的函数;
按照字符数据比较,最后一个参数传一个比较字符的函数; 所以最后一个参数为函数指针;根据上述思考,确定函数的参数和返回值
void bubble_sort(void*base, int num,int width,int(*cmp)(const void* e1,const void* e2))
void bubble_sort(void*base, int num,int width,int(*cmp)(const void* e1,const void* e2))
{
int i = 0;
for (i = 0; i < num - 1; i++)
{
int j = 0;
for (j = 0; j < num - 1 - i; j++)
{
if (cmp((char*)base + j*width, (char*)base + (j + 1)*width) > 0)
{
//交换俩个比较元素的位置;
//交换时只知道俩个元素的位置,还需知道每个元素的字节数即width;
//内存的最小单元为一个字节,一个字节一个字节的交换;
swap((char*)base + j*width, (char*)base + (j + 1)*width,width);
}
}
}
}
元素的具体类型未知,但是内存的最小单元是一个字节,我们将 void*类型的指针强制类型转换为 char*,一个字节一个字节的交换,swap()函数代码如下:
void swap(char* buf1, char*buf2, int width)
{
//一个字节一个字节的交换
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
使用bubble_sort排序整型数组
void swap(char* buf1, char*buf2, int width)
{
//一个字节一个字节的交换
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void*base, int num,int width,int(*cmp)(const void* e1,const void* e2))
{
int i = 0;
for (i = 0; i < num - 1; i++)
{
int j = 0;
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);
}
}
}
}
int cmp_int(const void*e1, const void*e2)
{
return *(int*)e1 - *(int*)e2;
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 10, 9, 5, 7, 6, 5, 4, 3, 2, 1 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr, sz);
return 0;
}
运行结果: