qsort 函数学习总结 - c语言库函数 - 快速排序且适应各种类型


前言

关于qsort函数的学习总结,还望点个赞!


一、函数介绍

函数功能:快速排序

函数使用形式:

需要引用头文件#include <stdlib.h>

void qsort( void *base, size_t num, size_t width, int ( *compare )(const void *elem1, const void *elem2 ) );

参数解释及为何使用

对于设计者:有以下几点未知

  1. 排序的元素类型及个数
  2. 排序的依据即如何比较

因此为了能使函数具备普遍性,因而设计了4个参数

对于第一个问题,设计了3个参数
  • void* base : void* 无类型指针用来存放任意类型的地址

  • size_t num : unsigned int num 用于存放元素个数

  • size_t width : unsigned int width 用于存放该类型元素的大小

对于第二个含数设计了1个参数 - 函数指针
  • int (* compare) (const void * elem1, const void* elem2) 该参数为函数指针,用于存放比较函数(自定义)
  • 返回值设为int 是因为规定结果被设计为 前’‘大‘’为 >0
    相等为 = 0,后’‘大’'为 <0
  • const细节:防止被比较的元素在函数内部被改变
  • void* 同样是为了适应各种类型

二、使用举例

整型比较

代码如下(示例):

#include <stdlib.h>
int compare1(const void* e1, const void* e2)
{
	//以int为例:对于无类型指针须转化为相应类型的指针
	//因此用到强制类型转换
	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(void)
{
	//排序整型
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);//求元素个数
	qsort(arr, sz, sizeof(arr[0]), compare1);
	print(arr, sz);
}

字符比较

浮点型比较

可类比整型


结构体比较

#include <stdlib.h>
struct stu
{
	char name[20];
	int age;
};
int sort_by_age(const void* e1, const void* e2)
{
	//比年龄
	return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
int sort_by_name(const void* e1, const void* e2)
{
	//比name
	return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
void test2()
{
	//排序结构体
	struct stu s[] = { {"zhangsan", 30},{"lisi", 34},{"wangwu", 20} };
	int sz = sizeof(s) / sizeof(s[0]);
	//按照年龄来排序
	qsort(s, sz, sizeof(s[0]), sort_by_age);
	//按照名字来排序
	qsort(s, sz, sizeof(s[0]), sort_by_name);
}

注意

  1. (struct stu*)e1 对于这个要用括号括起来 即 ((struct stu*)e1) 再用 -> 去访问,不然报错
  2. struct stu 结构体的定义须放这些代码的最上面,不然报错
  3. strcmp 字符串比较函数,自左向右逐个按照ASCII码值进行比较,直到出现不同的字符或遇’\0’为止。不是比较长度,若比较长度用strlen求长度,再比大小
    在这里插入图片描述

在这里插入图片描述


练习,模拟qsort函数的部分功能

模仿qsort函数实现一个冒泡排序的通用算法

void bubble_sort(void* base,
	size_t sz,
	size_t width,
	int(* compare)(const void* e1, const void* e2))
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		//一趟排序
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			//不知道是什么类型,因此先转化只有1字节访问权限的char*,
			//再加上 width * j - 即该类型所占字节大小
			if (compare((char*)base+width*j,(char*)base+(j+1)*width) > 0)
			{
				swap((char*)base + width * j, (char*)base + (j + 1) * width,width);
			}
		}
	}
}
void swap(char* e1, char* e2, int width)
{
     //e1 与 e2 分别指向 对应元素的首字节的地址
     //因此以1字节不断交换 width的大小,即可将两个元素交换
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *(e1);
		*(e1) = *(e2);
		*(e2) = tmp;
		e1++;//char*指针+1走一个字节,指针不要
		e2++;
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值