模拟实现qsort快速排序

目录

qsort介绍

模拟实现冒泡排序

整体框架

冒泡函数部分

比较函数部分

交换函数部分

模拟实现比较结构体

模拟实现比较浮点型数字

模拟实现比较字符串



qsort介绍

qsort函数是快速排序 适应于各种类型数据的排序,我们想要模拟实现它,就要先了解qsot函数函数模型,分析函数模型,为模拟实现做铺垫,

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

这个函数参数部分有三个,分别是 空指针定义的指针变量,base,size_t定义的 变量num,以及函数指针 compare指向的函数 它的参数 是两个被const 修饰的空指针变量;我们进一步看看这些元素都代表什么,

Return Value

None

Parameters

base

Start of target array

num

Array size in elements

width

Element size in bytes

compare

Comparison function

elem1

Pointer to the key for the search

elem2

Pointer to the array element to be compared with the key

base:目标数组起始位置         compare:比较函数

num:数组元素个数                  elem1:指向搜索元素

width:数组元素宽度                  elem1:指向与元素elem1进行比较的元素

除了比较函数 其他都是传参,我们看看 比较函数 具体实现了什么功能如下图所示,是返回两个元素比较的大小,如果大于 就返回大于0得数,等于就是0 小于就是返回小于零的数.

 我们可以从简单的冒泡排序 去将模拟实现qsort函数逐步完善,我发布过冒泡排序,可以去我的文章里搜一下看看 我讲的很详细。我直接把代码复制过来


#include<stdio.h>
 
// 冒泡函数
void bubble_sort(int arr[], int sz)
{
	//趟数
	int i = 0;
	for (i = 0; i < sz - 1; i++)// 因为只需要sz - 1趟,剩下的一个不要进去比较
	{
	{
		//一趟冒泡排序的过程
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++) // 比较完一个元素后,就会少比较一对 所以 上限在自减1
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
 
 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  test1()
{
	int arr1[10] = { 10,9,8,7,6,5,4,3,2,1 };//定义一个整形数组
	int sz = sizeof(arr1) / sizeof(arr1[0]);//计算元素个数
	bubble_sort(arr1, sz, sizeof(arr1[0]), cmp_int);// 参数 sizeof(arr1【0】)是一个元素的宽度,cmp_int 是比较函数,用来比较传输两个参数的大小
	//打印显示
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);

	}
}

冒泡函数部分

void bubble_sort(void* arr, size_t sz, size_t with, int(*cmp)(const void* e1, const void* e2))
{
	for (size_t i = 0; i < sz - 1; i++)
	{
		size_t j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			//强制类型转换成字节,一个一个字节比较
			if (cmp((char*)arr + j * with, (char*)arr + (j + 1) * with) > 0)
			{
				//比较完成后 进行交换
				swap((char*)arr + j * with, (char*)arr + (j + 1) * with,with);

			}
		}
    }

}

比较函数部分

//整形比较大小函数 返回类型是整形
int cmp_int(const void* e1, const void* e2) 
{
	return *(int*)e1 - *(int*)e2; // 返回两个元素相减的大小 
}

交换函数部分

void swap(char* e1, char* e2, size_t with)
{
	size_t i = 0;
	for (i = 0; i < with; i++)
	{
		char temp = *e1;
		*e1 = *e2;
		*e2 = temp;
		e1++;
		e2++;
	}
}

我们分析发现当接收到传过去元素宽度的时候,我们可以用字节*宽度,去交换任意类型的变量,所以我们用空指针接收,需要什么类型就强转什么类型。封装好排序函数,排序函数里 有指向比较函数的指针, 当调用排序函数时候,指针指向的比较函数也被启用,这就是比较有名的回调函数。


模拟实现比较结构体

typedef struct People

{
	char name[20];
	int age;
} people;

void test2()
{
	people s[3] = { {"zhangsan",20},{"lisi",30},{"wangwu",10} };
	int sz = sizeof(s) / sizeof(s[0]);
	bubble_sort(s, sz, sizeof(s[0]), cmp_by_name);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s ", s[i].name);

	}


int cmp_by_name(const void* e1, const void* e2)
{
	return (int) strcmp(((people*)e1)->name, ((people*)e2)->name);
}

模拟实现比较浮点型数字

void test3()
{

	double arr2[5] = { 1.23,5.16,3.23,4.31,2.34 };
	int sz = sizeof(arr2) / sizeof(arr2[0]);
	bubble_sort(arr2, sz, sizeof(arr2[0]), cmp_double);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%.2f ", arr2[i]);

	}

}
int cmp_double(const void* e1, const void* e2)
{
	// 强制类型转化成double 之后,两数相减,大于零 就让它返回1 小于零就让它返回 -1
	return ((*(double*)e1 - *(double*)e2) > 0) ? 1 : -1;
}

模拟实现比较字符串

void test4()
{
	char a[] = { 'a','c','e','d','b' };
	int sz = sizeof(a) / sizeof(a[0]);
	bubble_sort(a, sz, sizeof(a[0]), cmp_char);
	for (int i = 0; i < sz; i++)
	{
		printf("%c ", a[i]);
	}
int cmp_char(const void* e1, const void* e2)
{
	return *(char*)e1 - *(char*)e2;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值