模拟实现qsort函数的冒泡序列

该文章已生成可运行项目,

qsort函数

qsort函数是一种可以对任意类型的数据进行排序的函数,它的定义在<stdlib.h>头文件中,它的函数原型如下:

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

这个函数一共有四个参数,它们分别是:

  • 1.base:指向待排序数组的第一个元素的指针。

  • 2.num:数组中元素的个数。

    可以使用sizeof(arr)/sizeof(arr[0])来求出元素个数。

  • 3.size:每个元素的大小(以字节为单位)。

    可以使用sizeof(类型)求出,例如sizeof(int)。

    1. compar:指向比较函数的指针,该函数用于确定两个元素的顺序。

    qsort的使用

//排序整型数组
#include <stdio.h>
#include <stdlib.h>
int cmp(void* a, void* b)
{
	return (*(int*)a - *(int*)b);
}
//void qsort(void *base,
//	       size_t num,
//	       size_t size,
//	       int(*cmp)(const void*,const void*))
int main()
{
	int arr[] = { 9,7,6,5,8,4,2,3,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int size = sizeof(int);
	int i = 0;
	//打印原数组
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	qsort(arr, sz, size, cmp);
	//打印排序后的数组
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

qsort中的compar函数是需要自己编写的,它的作用是比较相邻两个元素的大小 ,它的返回值是int类型,有三种情况:

  • a>b -> 大于0
  • a<b - > 小于0
  • a=b -> 等于0
    输出结果为:(上方为原数组)

    (qsort默认是升序的,如果想降序可以将a,b调换一下)
//排序结构体数组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Stu
{
	char name[20];
	int age;
};
int cmp(const void* a, const void* b)
{
	return strcmp((*(struct Stu*)a).name, (*(struct Stu*)b).name);
	//这里排序Stu中的name字符串
}
int main()
{
	struct Stu arr[] = {{"zhangsan",20},{"lisi",30},{"wangwu",40} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int size = sizeof(arr[0]);
	int i = 0;
	qsort(arr, sz, size, cmp);
	for (i = 0; i < sz; i++)
	{
		printf("%s ", arr[i].name);
	}
	return 0;
}

字符串的比较是通过两个字符串中每位字符的ANSIC码值来比较的,例如”zhangsa“和“lisi”,"z"的码值比"l"大,所以“zhangsa”大。
结构体中调用其中的类型的方法有两种,一是**(结构体).(类型名)**,如(struct Stu a).name,另一种是(结构体指针)->(类型名),如((struct Stu*)a)->name。

冒泡排序对qsort的模拟实现

冒泡排序之前我们已经说过,它是一种将数据升序排列的方法,它的代码如下:

#include <stdio.h>
void bubble_sort(int arr[], int sz)
{
	int i = 0;
	int flag = 1;//假如初始时便是正序
	for (i = 0; i < sz - 1; i++)//趟数
	{
		int j = 0;
		for (j = 0; j<sz-i-1;j++ )
		{
			if (arr[j] > arr[j + 1])
			{
				flag = 0;//需要交换,就不是正序
				int tmp = 0;
				tmp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = tmp;
			}
			if (flag == 1)
			{
				break;//flag为1,即剩下的本就是正序,不需要再交换
			}
		}
	}
}
int main()
{
	int arr[] = { 3,1,7,4,2,6,8,9,0,5 };
	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 bubble_sort(int arr[], int sz)

对于int arr[],它的int类型应该变成void类型以便于接受任意类型的数据,仿照qsort的函数原型,我们将其变为:

void bubble_sort(void*base, size_t sz,size_t size,int(*cmp)(const void*e1,const void*e2))

那么如何向cmp函数传输某一个元素和下一个元素呢?我们可以这样:
我们之前传输了第一个元素的指针base和类型宽度size
在这里插入图片描述
我们可以将一个元素以字节为单位进行分割(以int为例)

在这里插入图片描述
如果将base强制转换为char *类型,根据char*的特点,char*+1移动一个字节,既然我们已经知道了类型长度size,那么(char*)base + 1*size便指向第二个元素arr[1],
(char*)base + j*size和(char*)base +(j+1)*size便指向arr[j]和arr[j+1]。
在这里插入图片描述
这样我们实现了任意类型的传输
总代码如下:

#include <stdio.h>
#include <string.h>
struct Stu
{
	char name[20];
	int age;
};
int cmp_int(void*base,size_t sz,size_t size,int j)
{
	return (*((char*)base + j * size)) - (*((char*)base + (j + 1) * size));
}
int cmp_struct(void* base, size_t sz, size_t size, int j)
{
	return  strcmp(((struct Stu*)((char*)base + j * size))->name, ((struct Stu*)((char*)base+ (j + 1) * size))->name);
}
void exchange(int(*cmp)(void* base, size_t sz, size_t size, int j),void* base, size_t sz, size_t size, int j)//交换
{
	if (cmp(base, sz, size, j) > 0&&size == sizeof(int))
	{
		int tmp = 0;
		tmp = (*((char*)base + (j + 1) * size));
		(*((char*)base + (j + 1) * size)) = (*((char*)base + j * size)) ;
		(*((char*)base + j * size)) = tmp;
    }
	else if(cmp(base, sz, size, j) > 0 && size == sizeof(struct Stu))
	{
		struct Stu tmp = *((struct Stu*)((char*)base + (j + 1) * size));
		*((struct Stu*)((char*)base + (j + 1) * size)) = *((struct Stu*)((char*)base + j * size));
		*((struct Stu*)((char*)base + j * size)) = tmp;
	}
}
void bubble_sort(void* base, size_t sz, size_t size)
{
	int i = 0;
	int flag = 1;//假如初始时便是正序
	for (i = 0; i < sz - 1; i++)//趟数
	{
		int j = 0;
		for (j = 0; j < sz - i - 1; j++)
		{
		//判断要交换数据的类型
			if (size == sizeof(int))
			{
			//交换
				exchange(cmp_int, base,sz, size, j);
			}
			else if(size == sizeof(struct Stu))
			{
				exchange(cmp_struct, base,sz, size, j);
			}
				flag = 0;
		}
			if (flag == 1)
			{
				break;//flag为1,即剩下的本就是正序,不需要再交换
			}
	}
}
void Print_int(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s ", arr[i]);
	}
}
void Print_Stu_name(struct Stu arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s ", arr[i].name);
	}
}
int main()
{
	struct Stu arr[] = {{"zhangsa",18},{"lisi",19},{"wanwu",20}};
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz,sizeof(arr[0]) );
	if (sizeof(arr[0]) == sizeof(int))
	{
		Print_int(arr, sz);
	}
	else if (sizeof(arr[0]) == sizeof(struct Stu)) 
	{
		Print_Stu_name(arr, sz);
	}
	return 0;
}
本文章已经生成可运行项目
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值