C笔记-冒泡排序的优化

C语言库里有qsort()函数来实现快速排序:

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

这是它的函数声明。

我们也能知道这个函数不仅可以对数字进行排序,也可以对各种数据类型进行排序,只是你需要自己写一个比较函数,即compare(const void *elem1, const void *elem2 );

鉴于此,我们可以对我们自己写的冒泡排序进行改造(当然你想改造选择排序也是可以的,我只是用冒泡做示范,偷偷说我有点喜欢冒泡,无理由哈哈),把它变成一个也可以排序任意类型数据的算法。

一下是代码汇总:(我会在下面分段介绍)

#include <stdio.h>

int cmp_int(const void* e1, const void* e2)
{
	if (*(int*)e1 > *(int*)e2)
		return 1;
	else if (*(int*)e1 == *(int*)e2)
		return 0;
	else
		return -1;
}

void swap(char* e1, char* e2,unsigned int width)
{
	int i;
	char temp;
	for (i = 0; i < width; ++i)
	{
		temp = *e1;
		*e1 = *e2;
		*e2 = temp;
		++e1;
		++e2;
	}
}

void sort(void* base, unsigned int num, unsigned int width, int(*cmp)(const void* e1, const void* e2))
{
	int i, j;
	int flag;
	for (i = 0; i < num - 1; ++i)
	{
        flag = 1;
		for (j = 0; j < num - 1 - i; ++j)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
				flag = 0;
			}
		}
		if (flag) break;
	}
}

int main()
{
	int arr[10] = { 1,4,2,3,6,7,9,5,8,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	sort(arr, sz, sizeof(int), cmp_int);
	for (int i = 0; i < 10; ++i)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

我定义了优化的冒泡排序函数sort()

参数和库函数中的qsort()一样:

第一个void *base是数组的起始地址

第二个unsigned int num是待排序数据元素的个数

第三个unsigned int width是待排序的数据元素的大小(单位byte)

最后一个int(*cmp)(const void* e1, const void* e2)是函数指针,用来比较大小

先看函数cmp_int(),它是用来比较数据大小的,他的返回值如下:

返回值规则
<0e1小于e2
=0e1等于e2
>0e1大于e2

再看swap(),这是用来交换数据的,它的实现原理很简单,就是把两个数据每个字节都交换,那不就相当于交换了两个数据了吗?

至于为什么参数和函数内部用char *和char类型来操作数据,在下面sort()函数里面解释

接下来是重要部分,就是sort()函数

基本框架还是冒泡排序(说人话就是两个嵌套的for循环)

其中的变量flag的作用我解释一下:在冒泡排序中,我们可能会遇到数据已经排序好的情况,这时候就不用再继续遍历,所以我们用flag来判断,每次进行最外层循环都将flag设为1,然后进入内层循环,当发生数据交换时设为0,结束内层循环后判断flag的值,如果为1说明数据已经有序,不用再进行外层循环,否则继续。(由此可知外循环至少进行1次)

再if中调用cmp函数,也就是外部传进来的cmp_int()函数,来判断数据的大小关系,先看参数base,它的类型是void *(泛类型指针),所以我们无法对它直接解引用和加减法,先强制类型转换为char *(因为char *一次就访问一个字节)然后加上移动量(j*width)获得目标地址,再传给cmp函数,同理再cmp函数里面也要先强制类型转换为char *再解引用

所以现在知道为什么cmp_int()的参数和函数内部要用char *和char类型来操作数据了吧?

然后结束!

没了!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值