qsort函数使用

138 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

大家好,我是芒果,一名非科班的在校大学生。对C/C++、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

作者简介:

2.qsort函数

函数说明:

image-20220214211810716

qsort()函数:快速排序的函数  -引用stdlib.h头文件
   
 参数说明:
void qsort(void* base, //要比较的数组
	size_t num,		//待排序的元素个数
	size_t width,	//一个元素的大小,单位是字节
	int(*cmp)(const void* e1, const void* e2));		//cmp指向的是:排序时,用来比较两个元素的函数

关于void*指针

void* :无具体类型的指针
  能够接收任意类型的地址
 缺点:不能进行运算。不能+-整数,不能解引用
int a  = 0;
float f = 5.5f;
void* p1 = &a;
void* p2 = &f;

排序整数数组

void Print(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(arr + i));
	}
	printf("\n");
}
//比较整形
//注意类型时void* 所以要强制类型转化,还要解引用才是对应的值!!!
int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
void test1()
{
	int arr[] = { 9,8,7,6,7,5,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	Print(arr, sz);
}

排序结构体数组

注意:结构体用大括号初始化

1.按名字比较->比较字符串-》strcmp函数

strcmp()返回值:和qsort刚好对应

strcmp()返回值

image-20220214211822849


qsort返回值

image-20220214211830611


struct Stu
{
	int age;
	char name[20];
};
//比较结构体中元素的年龄
int cmp_age(const void* e1, const void* e2)
{
	//本质是比较整形
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//比较名字
int cmp_name(const void* e1, const void* e2)
{
	//本质是字符串比较->使用strcmp函数
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
void test2()
{
	//创建结构体数组,用大括号初始化
	struct Stu s[3] = { {19,"Mango"},{18,"Lemon"},{20,"Hello"} };
	int sz = sizeof(s) / sizeof(s[0]);
	//以年龄排
	qsort(s, sz, sizeof(s[0]), cmp_age);
	printf("%s %d ",s[0].name,s[0].age);
	printf("%s %d ", s[1].name, s[1].age);
	printf("%s %d ", s[2].name, s[2].age);
	printf("\n");
	//以姓名排
	qsort(s, sz, sizeof(s[0]), cmp_name);
	printf("%s %d ", s[0].name, s[0].age);
	printf("%s %d ", s[1].name, s[1].age);
	printf("%s %d ", s[2].name, s[2].age);
	printf("\n");
}


排序浮点型数组

//写法1:可能会出错
// 原因: 0.2 -0.1 = 0.1 强制类型转化为int后 结果为0
//int cmp_float(const void* e1, const void* e2)
//{
//	//返回类型是int  所以相减后的结果要强制类型转化
//	return (int)(*(float*)e1 - *(float*)e2);
//}

//写法2:对应上qsort的返回值
int cmp_float(const void* e1, const void* e2)
{
	if ((*(float*)e1 - *(float*)e2) > 0.00000)
		return 1;
	else if ((*(float*)e1 - *(float*)e2) == 0.000000)
		return 0;
	else
		return -1;
}
void test3()
{
	float arr[5] = { 5.01f,5.01f,0.02f,0.01f,5.001f };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_float);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%f ", arr[i]);
	}
}

排序字符数组

//注意要要强制类型转换!! 要解引用!!!  本质上是比较Ascii值
int cmp_char(const void* e1, const void* e2)
{
    return *(char*)e1 - *(char*)e2;
}
void test4()
{
	char arr[] ="mango";
    //若使用sizeof计算长度:
	//int sz = sizeof(arr) / sizeof(arr[0]);	//6
	//qsort(arr, sz-1, sizeof(arr[0]), cmp_float);
    //因为sizeof把\0也算进去了,所以计算出来的值比字符串本身长度多1
    
    int sz = strlen(arr);	//5
    qsort(arr, sz, sizeof(arr[0]), cmp_char);
	printf("%s\n",arr);
}

排序字符指针数组

//err程序
int cmp_chars(const void* e1, const void* e2)
{
	return strcmp((char*)e1, *(char*)e2);
}
void test2()
{
	 char* arr1 = "abc";
	 char* arr2 = "wcad";
	 char* arr3 = "cab";
	 char* p[3] = { arr1,arr2,arr3 };
	int sz = sizeof(p) / sizeof(p[0]);
	qsort(p, sz, sizeof(p[0]), cmp_chars);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s\n", p[i]);
	}
}
上述程序错误原因:把p传给qsort,p是数组名->首元素地址,元素类型为char*>,所以p的地址类型为:char**类型

image-20220214211909913


//正确程序
//将e1和e2强制类型转化为char** 然后解引用找到对应的字符串的地址
int cmp_chars(const void* e1, const void* e2)
{
	return strcmp(*(char**)e1, *(char**)e2);
}
void test2()
{
	 char* arr1 = "abc";
	 char* arr2 = "wcad";
	 char* arr3 = "cab";
	 char* p[3] = { arr1,arr2,arr3 };
	int sz = sizeof(p) / sizeof(p[0]);
	qsort(p, sz, sizeof(p[0]), cmp_chars);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s\n", p[i]);
	}
}

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//qsort排序
//void qsort(void* base, //要比较的数组
//	size_t num,		//个数
//	size_t width,	//每一个元素的字节
//	int(__cdecl* compare)(const void* elem1, const void* elem2));

void Print(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(arr + i));
	}
	printf("\n");
}
//比较整形
int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
void test1()
{
	int arr[] = { 9,8,7,6,7,5,4,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	Print(arr, sz);
}

struct Stu
{
	int age;
	char name[20];
};
//比较结构体中元素的年龄
int cmp_age(const void* e1, const void* e2)
{
	//本质是比较整形
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//比较名字
int cmp_name(const void* e1, const void* e2)
{
	//本质是字符串比较->使用strcmp函数
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
void test2()
{
	//创建结构体数组,用大括号初始化
	struct Stu s[3] = { {19,"Mango"},{18,"Lemon"},{20,"Hello"} };
	int sz = sizeof(s) / sizeof(s[0]);
	//以年龄排
	qsort(s, sz, sizeof(s[0]), cmp_age);
	printf("%s %d ",s[0].name,s[0].age);
	printf("%s %d ", s[1].name, s[1].age);
	printf("%s %d ", s[2].name, s[2].age);
	printf("\n");
	//以姓名排
	qsort(s, sz, sizeof(s[0]), cmp_name);
	printf("%s %d ", s[0].name, s[0].age);
	printf("%s %d ", s[1].name, s[1].age);
	printf("%s %d ", s[2].name, s[2].age);
	printf("\n");
}

//比较浮点型数据
//写法1:可能会出错
// 原因: 0.2 -0.1 = 0.1 强制类型转化为int后 结果为0
//int cmp_float(const void* e1, const void* e2)
//{
//	//返回类型是int  所以相减后的结果要强制类型转化
//	return (int)(*(float*)e1 - *(float*)e2);
//}

//写法2:对应上
int cmp_float(const void* e1, const void* e2)
{
	if ((*(float*)e1 - *(float*)e2) > 0.00000)
		return 1;
	else if ((*(float*)e1 - *(float*)e2) == 0.000000)
		return 0;
	else
		return -1;
}
void test3()
{
	float arr[5] = { 5.01f,5.01f,0.02f,0.01f,5.001f };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_float);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%f ", arr[i]);
	}
    printf("\n");
}
//注意要要强制类型转换!! 要解引用!!!  本质上是比较Ascii值
int cmp_char(const void* e1, const void* e2)
{
    return *(char*)e1 - *(char*)e2;
}
void test4()
{
	char arr[] ="mango";
    //若使用sizeof计算长度:
	//int sz = sizeof(arr) / sizeof(arr[0]);	//6
	//qsort(arr, sz-1, sizeof(arr[0]), cmp_float);
    //因为sizeof把\0也算进去了,所以计算出来的值比字符串本身长度多1
    
    int sz = strlen(arr);	//5
    qsort(arr, sz, sizeof(arr[0]), cmp_char);
	printf("%s\n",arr);
}
int main()
{
	//排序整形数组
	test1();
	//排序结构体数组
	test2();
	//排序浮点型数据
	test3();
    //排序字符数组
    test4();
	return 0;
}