qsort函数详解

目录

qsort函数简介

qsort函数的使用

整型数组排序(升序)

cmp_int 函数实现方法一

cmp_int 函数实现方法二

代码总览(cmp函数采用方法二实现)

字符数组排序(升序)

cmp_char实现方法1

cmp_char实现方法2

代码总览(cmp函数采用方法二实现)

 浮点型数组排序(升序)

cmp_float实现方法1

cmp_float实现方法2

代码总览(cmp函数采用方法1实现)

代码总览(cmp函数采用方法2实现)

 结构体数组排序

 qsort()函数的模拟实现

使用bubble_sort排序整型数组


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;
}

运行结果:

 

  • 32
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小呆瓜历险记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值