【C语言】qsort函数使用及模拟实现

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


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值

  1. 如果e1小于e2 ,返回一个<0的数字
  2. 如果e1等于e2,返回一个0
  3. 如果e1大于e2,返回一个大于0的数字

关于 void* 的补充

  1. void*类型的指针 可以接收任意类型的地址
  2. void*类型的指针 不能进行解引用操作
  3. 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;
}

在这里插入图片描述

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值