C库函数 qsort()的使用与模拟实现

目录

​C 库函数- qsort()概念

​一个冒泡排序

         ​利用qsort解决

          ·void* 指针

 ​         ·qsort 实现

利用qsort结构体排序

 ​·​名字的排序

 ​·年龄的排序

​模拟实现qsort

​模拟qsort对数组的排序

        解析

​·主函数

​·比较函数

​·交换函数

​·基于冒泡排序的思想实现qsort的函数

​排序结构体数据

​·结果

 ​结束语


C 库函数<stdlib.h>- qsort()概念

qsort - 这个函数可以判刑任意类型的数据

为了防止歧义,这里引用了官方解释,下面我会详解

void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));

1.void* base //要排序的数据的起始位置

2.size_t num //待排序的数据元素的个数

3.size_t size  //待排序的数据元素的大小(单位是字节)

4.int (*compar)(const void*,const void*) //函数指针-一个比较函数

一个冒泡排序

//一个冒泡排序
void bubble_sort(int *arr, int sz)
{
	int i = 0;
	//趟数
	for ( i = 0; i < sz-1; i++)
	{
		int flag = 1;
		//交换
		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;
				flag = 0;
			}
		}
		if (flag)
		{
			break;
		}
	}
}

int main() {
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//升序排序
	int sz = sizeof(arr) / sizeof(arr[0]);

	bubble_sort(arr, sz);


	int i = 0;
	for ( i = 0; i < sz; i++)
	{
		printf("%d ",arr[i]);
	}


	return 0;
}

利用qsort解决

void* 指针

在开始代码的时候我们先要了解 void* 指针的类型

//void* 的作用

int main()
{
	int a = 10;
	char* pa = &a;		//warning C4133: “初始化”: 从“int *”到“char *”的类型不兼容
						//类型不兼容是会报警告的
	//void* pv = &a;    //这样子就不会有问题了
}

通常我们使用指针的时候都是一一对应,什么类型的数据地址就应该用什么类型的指针来接收,但有的情况下我们并不知道我们所接收的数据的类型是什么,因此便有了 void* 指针,这个类型的指针可以接收任意类型数据的地址,以来存储使用

 qsort 实现

 --使用的时候记得引入头文件 <stdlib.h>

​#include<stdlib.h>
#include<stdio.h>
int cmp_int(const void*e1, const void*e2) 
{
	return ( *(int*)e1 - *(int*)e2 );	//直接返回数据就行了
            //这是升序排序,当我们想要降序判刑只要交换e1、e2的位置就行了,逻辑交换的道理
}

int main() {
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//升序排序
	int sz = sizeof(arr) / sizeof(arr[0]);

	//bubble_sort(arr, sz);

	qsort(arr, sz, sizeof(arr[0]), cmp_int);

	int i = 0;
	for ( i = 0; i < sz; i++)
	{
		printf("%d ",arr[i]);
	}

	return 0;
}

​

//需要注意的是传过去的函数的规定
int compareMyType(const void* a, const void* b)
{
        if (*(MyType*)a < *(MyType*)b) return -1;    //返回一个小于0的数
        if (*(MyType*)a == *(MyType*)b) return 0;   //返回0
        if (*(MyType*)a > *(MyType*)b) return 1;    //返回一个大于0的数
}

//还要注意的是要强制类型

结果和冒泡排序的效果是一样的 

利用qsort结构体排序

 名字的排序

#include<stdlib.h>
#include<stdio.h>
#include<string.h>

struct Stu
{
	char name[20];
	int age;
};

cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
    //同样的需要强制转化类型成我们创立的结构体类型 (struct Stu*)
}

void test()
{
	//qsort来排序结构体数据
	struct Stu s[] = {{"zhangsan",15}, {"lisi",30}, {"wangwu",25}};  //创立一个结构体数据
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);    
}

int main() {

	test();

	return 0;
}

​

年龄的排序

#include<stdlib.h>
#include<stdio.h>
#include<string.h>

struct Stu
{
	char name[20];
	int age;
};

//按名字字母排序
cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

//按年龄的升序排序
cmp_stu_by_age(const void* e1, const void* e2)
{
	return  ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

void test()
{
	//qsort来排序结构体数据
	struct Stu s[] = {{"zhangsan",15}, {"lisi",30}, {"wangwu",25}};
	int sz = sizeof(s) / sizeof(s[0]);
	//qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}

int main() {

	test();

	return 0;
}

 一样的配方,一样的味道

模拟实现qsort

模拟qsort对数组的排序全代码

//模拟qsort对数组的排序
#include<stdio.h>

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);	//直接返回
			//这是升序排序,当我们想要降序判刑只要交换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++;
	}
}

//基于冒泡排序的思想实现qsort
void bubble_sort(void* base, int sz, int width, int (*cmp)(const void*e1, const void*e2))
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;
		//交换
		int j = 0;
		for (j = 0; j < sz - 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);
				flag = 0;
			}
		}
		if (flag)
		{
			break;
		}
	}
}

int main() {
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//升序排序
	int sz = sizeof(arr) / sizeof(arr[0]);

	//冒泡排序模拟qsort
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);

	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

解析

主函数

int main() {
    int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
    //升序排序
    int sz = sizeof(arr) / sizeof(arr[0]);

    //冒泡排序模拟qsort
    bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);  //这里毋庸置疑是把数组首元素的地址、

    int i = 0;                                                   //元素个数元素字节大小和一个比较函数的地址
    for (i = 0; i < sz; i++)                                //传给了我们自定义的函数bubble_sort
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;

比较函数

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);	//直接返回
							//这是升序排序,当我们想要降序判刑只要交换e1、e2的位置就行了,逻辑交换
}

交换函数

void Swap(char* buf1, char* buf2, int width)   //接收数据的宽度,这样在下面的循环中就可以
{                                                                       //保证正常循环不溢出
    int i = 0;
    for (i = 0; i < width; i++) //需要注意的是这里是字节的交换哦,全部字节交换也就是数据交换
    {                                   //在一开始我们是默认不知道传过来的数据是什么类型的
        char tmp = *buf1;   //因此我们使用char类型开始,这样什么类型的开始都可以向后找到
        *buf1 = *buf2;        
        *buf2 = tmp;
        *buf1++;
        *buf2++;
    }

基于冒泡排序的思想实现qsort的函数

void bubble_sort(void* base, int sz, int width, int (*cmp)(const void* e1, const void* e2))
{
    int i = 0;
    //趟数
    for (i = 0; i < sz - 1; i++)
    {
        int flag = 1;
        //交换
        int j = 0;
        for (j = 0; j < sz - 1 - i; j++)
        {
            if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
            {      //这里将它转为为chaf*类型的指针,再加上元素位置乘以一个宽度,这样就可以
                //交换                                                                        //找到对应的元素了
                Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
                flag = 0;                                                //这里记得把宽度传过去,便于后面交换
            }
        }
        if (flag)
        {
            break;
        }
    }

排序结构体数据

​
#include<stdio.h>
#include<string.h>

 struct Stu
{
	char name[20];
	int age;
};


int cmp_int(const void*e1, const void*e2) 
{
	return ( *(int*)e1 - *(int*)e2 );	//直接返回
							//这是升序排序,当我们想要降序判刑只要交换e1、e2的位置就行了,逻辑交换
}


cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

cmp_stu_by_age(const void* e1, const void* e2)
{
	return  ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

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


//基于冒泡排序的思想实现qsort
void bubble_sort(void *base, int sz,int width,int (*cmp)(const void* e1 , const void* e2))
{
	int i = 0;
	//趟数
	for ( i = 0; i < sz-1; i++)
	{
		int flag = 1;
		//交换
		int j = 0;
		for ( j = 0; j < sz-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);
				flag = 0;
			}
		}
		if (flag)
		{
			break;
		}
	}
}

void test()
{
	//qsort来排序结构体数据
	struct Stu s[] = { {"zhangsan",15}, {"lisi",30}, {"wangwu",25} };
	int sz = sizeof(s) / sizeof(s[0]);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);//如果按名字排序,改函数名字就可以了
}                                                    //cmp_stu_by_name

int main() {

	//结构体排序
	test();

	return 0;
}

​

结果

按年龄

 按姓名

 结束语

                                四年

四年很快啊,暮然之际已经过去一年了,我进入学习编程也已经一个学期半年时光了,用这个记录自己学习的时光,以后就可以回顾这些记忆了……

未完持续更新中…… 

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

清风玉骨

爱了!

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

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

打赏作者

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

抵扣说明:

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

余额充值