qsort的模拟实现

qsort是一个排序函数,它可以排序整形,字符型甚至是结构体,下面让我们看看qsort函数是如何实现不同类型的排序

对于qsort,返回的类型是void类型,传递的形参有四个,分别是待排序数组的第一个对象首元素的地址;数组中元素的个数;每个元素的大小;以及一个比较函数。

下面先让我们来看qsort中形参的比较函数:

在比较函数中,无论是整型还是字符型元素,在计算机中都是以ASCII码的形式进行存储与计算,那么比较函数的返回值类型应该是int 类型。

而对于形参,我们应当遵循int cmp(const void*e1,const void*e2)的形式。因为void*类型的指针可以接收任何类型的指针。

假如现在用qsort排序一个整型字符,那么比较函数中的形参接收到的就是两个整型的指针,在返回值中必须将void类型的指针强制转换成int类型的指针:

int arr_sub(const void*e1,const void*e2) {
	return (*(int*)e1 - *(int*)e2);
}

对于qsort排序一个字符型数组,那么在返回值中需要将void类型指针强制转换成char类型再进行比较,刚好在库函数中有一个strcmp函数,就是用来比较字符大小的,我们可以利用它:

int arr_sub(const void*e1,const void*e2) {
	return strcmp((char*)e1, (char*)e2);
}

最后对于结构体的比较函数,就显得复杂一点,需要根据结构体成员的类型来进行确定比较函数的返回值:

struct stu
{
	char name[20];
	int age;
	int num;
};
//比较名字
int cmp_name(const void* e1, const void* e2) {
	return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);//利用库函数进行比较
}
//比较年龄
int cmp_age(const void* e1,const void* e2) {
	return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
//比较学号
int cmp_num(const void* e1, const void* e2) {
	return ((struct stu*)e1)->num - ((struct stu*)e2)->num;
}

以下是利用qsort来实现冒泡排序:

int arr_sub(const void*e1,const void*e2) {
	return strcmp((char*)e1, (char*)e2);
}
int main() {
	int arr[] = { 'a','e','d','g','k','b'};
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(int), arr_sub);
	for (int i = sz-1; i >=0 ; i--) {
		printf("%c\n", arr[i]);
	}
}

结果如下: 

按照qsort的实现逻辑,我们也可以自己来进行模拟实现。

模拟实现中的比较函数与库函数中的交换函数一致,只需要注意此时排序的是什么类型的数组。

在交换函数中,我们不确定待排序的数组是什么类型,所以我们直接通过字节来交换,因为数组中元素类型一致,通过强制转换成char类型再解引用进行字节的交换。

最后是最主要的逻辑:冒泡排序

#include<stdio.h>
#include<assert.h>
//qsort函数形参:地址,元素个数,每个元素的字节数的大小,比较函数
int cmp(const void* e1, const void* e2) {
	return *(int*)e1 - *(int*)e2;
}
//交换函数(两个元素之间的交换)
//一个字节一个字节的交换,直到交换的字节数等于一个元素的字节数
void swap(void*p1,void*p2,int size) {//指向两个字节,每个元素的大小
	for (int i = 0; i < size; i++) {
		/*char temp = *(char*)p1;
		*(char*) p2 =*(char*)p1;
		*(char*)p1 = temp;*/
		/*p1 = (char*)p1 + 1;
		p2 = (char*)p2 + 1;*/
		char temp = *((char*)p1 + i);
		*((char*)p1 + i)= *((char*)p2 + i);
		*((char*)p2 + i)=temp;
	}
}
//通过冒泡排序的样式对每个字节都进行交换,因为不确定元素的类型
void my_qsort(int*arr,int sz,int size,int(*cmp)(const void*,const void*)) {
	for (int i = 0; i < sz-1; i++) {
		for (int j = 0; j < sz - i - 1; j++) {
			// j * size与(j + 1) * size跳过一个元素
            //两个元素的第一个字节就可以判断出这两个元素的大小
			if (cmp((char*)arr + j * size, (char*)arr + (j + 1) * size) > 0) {
				swap((char*)arr + j * size, (char*)arr + (j + 1) * size,size);
			}
		}
	}
}
int main() {
	int arr[] = { 1,3,2,8,5,4,7,0,9,65 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	my_qsort(arr,sz,sizeof(int), cmp);
	for (int i = 0; i < sz; i++) {
		printf("%d", arr[i]);
		printf("\n");
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值