提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
qsort函数的基本信息
qsort()函数功能是对数组进行有序的排序。可用于任何数据类型的排序。
上图是MSDN上对qsort的介绍
qsort() 函数有四个参数
void qsort(1: void* base, 2: size_t num, 3: size_t width, 4: int( *cmp)(const void *e1, const void e2))
第一个元素 base:待排序数组的首元素地址
第二个元素 num:待排序数组共几个元素
第三个元素 width:该数组每个元素的大小-单位字节
第四个元素 cmp:用于确定排序时的升序降序,要求使用者提供一个自己定义的比较函数 , cmp参数是qsort函数排序的核心内容,它指向一个比两较个元素的函数,注意两个形参必须是const void型(在运行期间是不能更改参数1或参数2的值的,所以为保险起见,我们可以给两个参数前加上const修饰,来使参数指向的数值无法改变)
小补充:
const修饰的指针,在符号左边即为固定指向的值不可改变,在符号右边则为固定指针指向的方向不可改变。可以简记为:左定值,右定向。
下面是cplusplus.com上对qsort的几个参数的说明
第四个元素 int( * cmp )(const void *e1, const void *e2)
比较函数cmp的作用就是给qsort指明元素的大小是如何比较的, 比较函数返回值是一个int值
- 如果e1小于e2 ,返回一个<0的数字
- 如果e1等于e2,返回一个0
- 如果e1大于e2,返回一个大于0的数字
关于 void* 的补充
- void*类型的指针 可以接收任意类型的地址
- void*类型的指针 不能进行解引用操作
- void*类型的指针 不能进行±整数的操作
几种常见的cmp定义形式
//整形数组升序排法
int cmp_int(const void* e1, const void* e2)
{
return (*(int*)e1) - (*(int*)e2);
//降序为 return (*(int*)e1) + (*(int*)e2)
//后者一样
}
//浮点型数组升序排法
int cmp_float (const void* e1, const void* e2)
{
return ((int)((float*)e1 - (float*)e2));
}
//字符型数组升序排法
int cmp_char (const void* e1, const void* e2)
{
return strcmp((char*)e1, (char*)e2)
//降序为 return strcmp((char*)e2, (char*)e1)
}
//结构体中的排序
struct stu
{
int age;
char name[20];
double grade;
}
//按结构体中的整形排序
int cmp_struct_int (const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}
//按结构体中的浮点形排序
int cmp_struct_flost (const void* e1, const void* e2)
{
return ((struct Stu*)e1)->grade - ((struct Stu*)e2)->grade);
}
//按结构体中的字符形排序
int cmp_struct_name(const void* e1, const void* e2)
{
return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
qsort函数的使用过程
int main()
{
//用qsort函数实现
printf("用qsort函数实现\n");
int arr[] = { 0,5,6,3,7,8,4,2,1,9,5,6,1 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
struct stu ra[] = { {"wangwu",18} ,{"lisi",30}, {"zhangsan",10} };
int szz = sizeof(ra) / sizeof(ra[0]);
qsort(ra, szz, sizeof(ra[0]), cmp_stu_age);
for(int i=0;i<szz;i++)
{
printf("%s %d ", ra[i].name, ra[i].age);
}
printf("\n");
qsort(ra, szz, sizeof(ra[0]), cmp_stu_name);
for (int i = 0; i < szz; i++)
{
printf("%s %d ", ra[i].name, ra[i].age);
}
return 0;
}
下图为MSDN上qsort的使用案例
模拟实现
函数体内部逻辑整体参考冒泡排序,只在一小部分地方有略微的改动。首先因为我们在整个bubble()函数中都不知道base传进的参数到底是什么类型的,因此索性不去纠结数据的类型,干脆将他们统一视为一个字节一个字节的空间来进行比较及交换,因此传入bubble()函数的指针统一强制类型转换成char*类型,以便后续我们一个字节一个字节操作。该部分代码及解析如下:
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{
for (int i = 0; i < count - 1; i++)
{
for (int j = 0; j < count - i - 1; j++)
{
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
{
_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
}
}
}
}
我们并不知道该数据的类型,只知道该数据的大小sz
所以将他们统一视为一个字节一个字节的空间来进行比较及交换,所以自定义 _swap 函数
_swap(const void* p1, const void* p2, int size)
{
for (int i = 0; i < size; i++)
{
char tmp = *((char*)p1 + i);
*((char*)p1 + i) = *((char*) p2 + i);
*((char*)p2 + i) = tmp;
}
}
整体代码实现(包含qsort函数和自定义的bubble函数)
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//模仿qsort的功能实现一个通用的冒泡排序
//交换
_swap(const void* p1, const void* p2, int size)
{
for (int i = 0; i < size; i++)
{
char tmp = *((char*)p1 + i);
*((char*)p1 + i) = *((char*) p2 + i);
*((char*)p2 + i) = tmp;
}
}
//bubble代替qsort
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{
for (int i = 0; i < count - 1; i++)
{
for (int j = 0; j < count - i - 1; j++)
{
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
{
_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
}
}
}
}
//练习使用库函数,qsort排序各种类型的数据
//使⽤qsort函数排序整型数据
//qosrt函数的使⽤者得实现⼀个⽐较函数
//
//整数比较
int cmp_int(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
//结构体比较
struct stu
{
char name[10];
int age;
};
int cmp_stu_age(const void* p1, const void* p2)
{
return (((struct stu*)p1)->age - ((struct stu*)p2)->age);
}
int cmp_stu_name(const void* p1, const void* p2)
{
return strcmp(((struct stu*)p1)->name, ((struct stu*)p2)->name);
}
int main()
{
//用qsort函数实现
printf("用qsort函数实现\n");
int arr[] = { 0,5,6,3,7,8,4,2,1,9,5,6,1 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
struct stu ra[] = { {"wangwu",18} ,{"lisi",30}, {"zhangsan",10} };
int szz = sizeof(ra) / sizeof(ra[0]);
qsort(ra, szz, sizeof(ra[0]), cmp_stu_age);
for(int i=0;i<szz;i++)
{
printf("%s %d ", ra[i].name, ra[i].age);
}
printf("\n");
qsort(ra, szz, sizeof(ra[0]), cmp_stu_name);
for (int i = 0; i < szz; i++)
{
printf("%s %d ", ra[i].name, ra[i].age);
}
printf("\n");
printf("\n");
printf("\n");
printf("用bubble函数实现\n");
//用bubble函数实现
bubble(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
bubble(ra, szz, sizeof(ra[0]), cmp_stu_age);
for (int i = 0; i < szz; i++)
{
printf("%s %d ", ra[i].name, ra[i].age);
}
printf("\n");
bubble(ra, szz, sizeof(ra[0]), cmp_stu_name);
for (int i = 0; i < szz; i++)
{
printf("%s %d ", ra[i].name, ra[i].age);
}
return 0;
}