模拟实现qsort函数

冒泡排序的工作原理

它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

一般冒泡排序 

一般的冒泡排序只适用于特定类型元素的排序,例如只能排整形元素,对于浮点型或者结构体就不再适用,这是它的一大缺点。

推广后的冒泡排序

推广后的冒泡排序既可以排序整形数组,又可以排浮点型和结构体。但相对与一般的冒泡排序,推广后的冒泡排序实现起来相对复杂,需要耐心地去理解。

知识铺垫

void*

>void*类型的指针可以接收任意类型的地址

>void*类型的指针不能进行解引用操作,因为void*无具体类型,访问几个字节不确定

>void*类型的指针不能进行+-整数的操作,因为void* 无具体类型,一次向前或向后跳几个字节不确定

qsort函数---任意类型数组排序的通用函数,结构体也可以
void qsort( 1 , 2 , 3 , 4 )
>1 待排序数组的首元素地址,一般情况下为数组名。
>2 待排序数组的元素个数
>3 待排序数组的每个元素大小
>4 接收比较函数的指针(比较函数需自己定义)---该函数的两个参数是待比较的两个元素的地址
    qsort(arr, sz1, sizeof(arr[0]), cmp_int);
【.】可以对结构体的内容进行访问

自己实现的推广冒牌排序就是模仿上述库函数来实现的。

代码还会涉及到强制类型转换等知识。下面请看代码(可复制 ):

                                                                   代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

struct student
{
	char name[20];
	int age;
};
void Swap(char* buf1, char* buf2, int width)
    //把宽度传过来才知道一个元素有几个字节,要交换几次
{
	int i = 0;
	for (i = 0; i < width; i++)
	//每完成一趟循环交换一个字节,利用了char++跳过一个字节的特性
	{
		char tmp = 0;
		tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}

//整形的比较方法
int cmp_int(void* e1, void* e2)
{
	return *(int*)e1 - *(int*)e2;
}

//浮点型的比较方法
 int cmp_float(const float* e1, const float* e2)
{
	return (int)(*(float*)e1) - (int)(*(float*)e2);
}

 //结构体的比较方法
 int cmp_stu_s_by_age(const void* e1, const void* e2)
 {
	 	return ((struct student*)e1) ->age  - ((struct student*)e2) ->age;
 }
 


void bubble_sort(void* base, int sz, int width, int (*cmp)(void* e1, void* e2))
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)//i表示趟数,比元素个数少1
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)//每一趟中要比较的对数
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)//升序
			{
		//(char*)base指向第一个元素,加上width后,正好跳过一个int类型的宽度,指向下一个元素
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}
void test1()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);//调用自定义的排序函数

	int i = 0;
	for (i = 0; i < sz; i++)//打印排列后的数组元素
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

void test2()
{
	float f[] = { 9.0,8.0,7.0,6.0,5.0,4.0 };
	int sz = sizeof(f) / sizeof(f[0]);

	bubble_sort(f, sz, sizeof(f[0]), cmp_float);

	int n = 0;
	for (n = 0; n < sz; n++)
	{
		printf("%f ", f[n]);
	}
	printf("\n");
}


void test3()
{
	struct student s[] = { {"zhangsan",20},{"lisi",15},{"wangwu",13} };
	bubble_sort(s, 3, sizeof(s[0]), cmp_stu_s_by_age);

	int n = 0;
	for (n = 0; n < 3; n++)
	{
		printf("%d ", s[n].age);
	}
}
int main()
{
	test1();//整形
	test2();//浮点型
	test3();//结构体

	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值