5000多字带你掌握qsort函数

一 . 认识qsort函数

在这里插入图片描述
💛📑📖💛👇👇👇

 qsort函数是C语言库里的排序函数,能够实现多种数据类型的排序,其头文件包含在<stdlib.h>。参数解释如下 
void qsort( void *base, size_t num, size_t width, int (*cmp )(const void *elem1, const void *elem2 ) );
1.base 待排序数组的初始地址;base的类型为void * 是为了接收各种类型的数据,从而实现对多种类型的数据排序
2.num 数组中元素个数
3.width 数组中一个元素占几个字节大小
4.cmp 比较函数---这是qsort函数实现的精髓,通过自己实现比较函数的编写来规定qsort函数按照怎样的方式去排序(不同数据类型不同,升序降序也不同)

❗️❗️cmp函数的返回值有明确规定

在这里插入图片描述

💥👊✌️废话不多说,直接上手实现怎么使用qsort函数👏📖✌️

二. qsort 函数的实现

1️⃣整型数组排序

#include<stdio.h>
int int_cmp(const void*e1,const void*e2)//自己编写cmp函数规定qsort函数按照什么样的规则去排序,
{
    return (*(int*)e1-*(int*)e2);    //先把e1,e2强制转化成int* 然后解引用后相减如果*e1>*e2 就返回大于零的值,小于就返回小于0的值。满足cmp的返回规则
}
int main()
{
  int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
  int i = 0;
  qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
  for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
 {
   printf( "%d ", arr[i]);
 }
  printf("\n");
  return 0;
}

​ 代码运行结果👇👇👇
在这里插入图片描述

2️⃣浮点型数组的实现

注意!!!比较函数中返回值为int类型,在比较浮点数时强制转化成int类型时可能会出错,例如 9.9-9.8=0.2int)(0.2=0;导致判断出错,应注意此时和int类型排序的不同
#include<stdio.h>
int float_cmp(const void*e1,const void*e2)
{
    if((*(float*)e1-*(float*)e2) > 0.00000)
        return 1;
    if(((*(float*)e1-*(float*)e2)) == 0.00000)
       return 0;
    else
        return -1;
}
int main()
{
  float arr[] = { 1.561, 0.456, 0.789, 7.123, 9.598, 2.598, 4.458, 6.123, 8.458, 0.000 };
  int i = 0;
  qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (arr[0]), float_cmp);
  for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
 {
   printf( "%f ", arr[i]);
 }
  printf("\n");
  return 0;
}

运行结果如下:👇👇👇

在这里插入图片描述

3️⃣字符数组排序

#include<stdio.h>
int char_cmp(const void*e1,const void*e2)
{
    return(*(char*)e1 - *(char*)e2);//比较字符的大小实际是比较字符ASII码的大小,所以直接返回两个字符相减的值。
}
int main()
{
  char arr[] = "rjc321"
  int i = 0;
  int sz = strlen(arr);
  qsort(arr, sz, sizeof (arr[0]), char_cmp);
  for (i = 0; i < sz; i++)
 {
   printf( "%c ", arr[i]);
 }
  printf("\n");
  return 0;
}

运行结果如下:👇👇👇

在这里插入图片描述

4️⃣结构体数组排序

因为我们定义的结构体里面含有不同种数据类型,所以在进行结构体排序时,比较函数应根据要比较结构体中待比较元素的数据类型来确定
struct Stu
{
	char name[20];
	int age;
	double score;
};

int cmp_stu_by_age(const void* e1, const void*e2)//比较结构体中的年龄,实际就是整型数组的比较
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

int cmp_stu_by_name(const void* e1, const void* e2)//比较结构体中的名字,实际是字符串的比较,使用strcmp函数
{
	return strcmp( ((struct Stu*)e1)->name , ((struct Stu*)e2)->name);
}
//使用strcmp函数比较字符串时实际是一个一个字符的比较,也就是字符串中各个字符ASII码值的比较
//abc ad----> 返回值<0
//cba abc----> 返回值>0    
//abc abc-----> 返回值=0 
void test()
{
	struct Stu arr[3] = { {"zhangsan", 20, 55.5},{"lisi", 30, 88.0},{"wangwu", 10, 90.0}};
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);//按年龄
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);//按名字
}

按名字排序👇👇👇
在这里插入图片描述
按年龄排序👇👇👇
在这里插入图片描述

5️⃣指针数组排序

!!!指针数组是数组,数组里面存放的是指针,如下图所示数组里面存放的分别是指向各个字符串的指针,类型为char*,str指向的是该指针数组的指针,所以str的类型是char**,所以强制类型转化时应该把str强制转化为char**,然后解引用才能找到char*的arr 进行比较

在这里插入图片描述

int cmp_pchar(const void* e1, const void* e2)
{
    return strcmp(*(char**)e1, *(char**)e2);
}
void test()
{
          char* arr1 = "cbc";
          char* arr2 = "acd";
          char* arr3 = "bde";
        char* str[3] = { arr1,arr2,arr3 };
        qsort(str, sizeof(str) / sizeof(str[0]), sizeof(str[0]),cmp_pchar);
    int i = 0;
    for (i = 0; i < sizeof(str) /sizeof( str[0]); i++)
    {
        printf("%s\n", str[i]);
    }
}
int main()
{
    test();
    return 0;
}

运行结果如下:👇👇👇

在这里插入图片描述

6️⃣降序排列

在之前的基础上实现降序排列,只需要与cmp返回值的逻辑相反即可,e1所指向的元素大于e2所指向的元素时cmp返回大于0的数,
要实现逻辑相反只需要把e1-e2改成e2-e1即可。
#include<stdio.h>
int int_cmp(const void*e1,const void*e2)
{
    return (*(int*)e2-*(int*)e1);    
}
int main()
{
  int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
  int i = 0;
  qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
  for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
 {
   printf( "%d ", arr[i]);
 }
  printf("\n");
  return 0;
}

运行结果如下:👇👇👇

在这里插入图片描述

三 . 模拟实现qsort(冒泡排序升级版)

1️⃣冒泡排序

😍👇✌️🔥先上动图
在这里插入图片描述

整体思想:一共排n-1趟,每一趟相邻两个元素比较大小把大的元素排到最后,最后实现所有元素的升序排列
缺点:只能排序整形数组
void bubble_sort(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz-1-i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

2️⃣升级版

运用冒泡排序思想和qsort排序理论实现冒泡排序升级,可以排序多种数据类型的数组
细节1.将base强制转化为char*指针,这样处理的话char*+1 跳过一个字节,+width跳过width个字节,相当于跳过一个元素,这样不管是什么类型的元素进行比较时,只要给出一个元素占多少个字节(width)我们就可以利用+width来指向下一个元素,粒度达到最细。适用于多种类型的数据.

在这里插入图片描述

if(cmp((char*)base + j * width, (char*)base + (j + 1) * width)>0)
j=0时比较的是第一和第二个元素,j=1时比较的是第2和第三个元素
细节2;swap交换函数 当cmp>0时要交换e1,e2所指向元素的内容 这里的实现方法是通过传地址,然后一个字节一个字节的交换.
!数据在内存中是以小端存储的方式存储的。
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 print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

int cmp_stu_by_age(const void* e1, const void*e2)//比较结构体中的年龄,实际就是整型数组的比较
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

int cmp_stu_by_name(const void* e1, const void* e2)//比较结构体中的名字,实际是字符串的比较,使用strcmp函数
{
	return strcmp( ((struct Stu*)e1)->name , ((struct Stu*)e2)->name);
}
int int_cmp(const void*e1,const void*e2)//自己编写cmp函数规定qsort函数按照什么样的规则去排序,
{
    return (*(int*)e1-*(int*)e2);    //先把e1,e2强制转化成int* 然后解引用后相减如果*e1>*e2 就返回大于零的值,小于就返回小于0的值。满足cmp的返回规则
}
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);
			}
		}
	}
}

void test1()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
        
        
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}

void test2()
{
	struct Stu arr[3] = { {"zhangsan", 20, 55.5},{"lisi", 30, 88.0},{"wangwu", 10, 90.0} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
	//bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}

😄😄😄✌️😄✌️😄结语

由于自己还是萌新小白阶段,功力有限,如果本篇文章所包含的知识点存在我理解错误或者使用不当的地方,欢迎各位大佬斧正。

😋😴😴

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值