c语言中冒泡排序函数 和 qsort快速排序函数的比较。 自定义实现一个qsort函数。。。万能排序函数原来如此 111

本文详细介绍了C语言冒泡排序算法及其优化,重点讲解了如何利用qsort函数进行不同类型数据的排序,包括自定义比较函数和针对不同数据结构的排序示例。讨论了如何通过字节交换实现任意类型数据的排序,并给出了完整的my_qsort函数实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

冒泡排序函数:

冒泡排序函数是c语言中比较经典的排序函数,他对数组的排序可以很好实现,正序,逆序都没问题。

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int arr[] = { 9,6,5,4,8,7,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz - 1; i++)//10个元素,
	//只需要进行9趟排序,n个元素,只需要进行n-1趟排序
	{
		for (int j = 0; j < sz - 1 - i; j++)
//第一次排序时,10个元素只需要比9次,第二次排序时
//对第一次排序时已经移动到最前面的数据,不需要再进行比较
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

关键点

    for (i = 0; i < sz - 1; i++)//10个元素,
    //只需要进行9趟排序,n个元素,只需要进行n-1趟排序
    {
        for (int j = 0; j < sz - 1 - i; j++)
//第一次排序时,10个元素只需要比9次,第二次排序时
//对第一次排序时已经移动到最前面的数据,不需要再进行比较

//所以这里每一次比较的次数 j 范围是 sz - 1 - i

但是冒泡排序不能实现任意类型的数据排序 ,所以这里就体现出了qsort函数的便捷性。

(  但是在使用qsort函数时需要自己写出一个某种类型的比较函数  

我们先来了解一个qsort函数的定义方式:

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

void qsort(void* base,         // 空类型指针,
                                             // 可以接收任意类型地址    用来接收待排序数据元素首地址
   size_t num,             //接收待排序数据的个数
  size_t width,           //待排序数据的每个元素位宽,每个元素占字节个数。
    int(* compare)(const void* elem1, const void* elem2))
                          //自己定义所需要的某种类型比较函数

还是通过一个整形数组的例子来了解一个

 这里需要自己定义一个   int cmp_int(void const * p1, void const * p2) 函数。

我们再来看一种对结构体类型数据排序的例子

首先定义结构体:

struct stu
{
    int age;
    char name[20];
};

然后自定义出两种排序结构体的函数:

int sort_by_age(const void * p1,const void * p2)//通过年纪排序
{
    return  (((struct stu*)p1)->age) - (((struct stu*)p2)->age);//年纪整型数据,直接减
}
int sort_by_name(void const* p1, void const* p2)//通过名字排序
{
    return strcmp( ( ( struct stu * ) p1 )->name, ( ( struct stu * )p2 )->name);

//字符的比较要通过strcmp函数实现。
}

实现结果如下:

 代码如下:

struct stu
{
	int age;
	char name[20];
};
int sort_by_age(const void * p1,const void * p2)
{
	return  (((struct stu*)p1)->age) - (((struct stu*)p2)->age);
}
int sort_by_name(void const* p1, void const* p2)
{
	return strcmp( ( ( struct stu * ) p1 )->name, ( ( struct stu * )p2 )->name);
}
int main()
{
	struct stu s[] = { {23,"zhangsan"} ,{34,"lisi"} ,{15,"wanwu"}};
	size_t sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), sort_by_name);
	printf("通过名字排序:\n");
	for (int i = 0; i < sz; i++)
	{
		printf("%d   %s\n", s[i].age, s[i].name);
	}
	printf("\n\n");
	printf("通过年纪排序:\n");
	qsort(s, sz, sizeof(s[0]), sort_by_age);
	for (int i = 0; i < sz; i++)
	{
		printf("%d   %s\n", s[i].age, s[i].name);
	}
	return 0;
}

自定义的qsort函数

这个函数最关键的一个点在于两个数据的交换。

因为在官方定义的qsort函数里,我们只需要提供一个比较函数,返回比较的值,返回的值大于0(前面的值大于后面的值) ,交换两个数据,小于0(前面的值小于后面的值)不交换。

那对于这些不知道类型的数据要怎么进行交换呢 ???

我们都知道,数据在内存中都是以二进制的形式存储的,存储的都是二进制码,而最小的数据类型是一个字节的大小,所有的其他数据类型都是一个字节的整数倍。那么我们可不可以对两个数据进行一个字节一个字节的交换呢。

下面我们对两个int类型的数据进行一个字节一个字节交换的测试:

可以看到结果是如我们预测的那样。对于两个int类型的数据,确实可以进行一个字节一个字节的交换方式。 那么我们只需要知道交换的两种变量类型的字节大小。将其作为循环判断的条件,就可以交换完成两个任意类型的数据了。

正好在qsort函数的定义里  所需要的函数参数有一个就是这个类型数据的位宽。

分析完成 函数代码实现如下:

struct stu
{
	int age;
	char name[20];
};
int sort_by_age(const void * p1,const void * p2)
{
	return  (((struct stu*)p1)->age) - (((struct stu*)p2)->age);
}
int sort_by_name(void const* p1, void const* p2)
{
	return strcmp( ( ( struct stu * ) p1 )->name, ( ( struct stu * )p2 )->name );
}
void swp(const void * p1, const void * p2, size_t width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *((char*)p1+i);
		*((char*)p1+i) = *((char*)p2+i);
		*((char*)p2+i) = tmp;
	}
}
void my_qsort(void* base,
	size_t num,
	size_t width,
	int(* com)(const void* elem1, const void* elem2)  )
{
	int i = 0;
	for (i = 0; i < num - 1 ; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			if ( com( ( (char*)base + j * width ) ,( (char*)base + (j + 1)*width )) > 0 )
			{
				swp( (char*)base + j * width , (char*)base + (j + 1) * width , width );
			}
		}
	}
}
int main()
{
	struct stu s[] = { {23,"zhangsan"} ,{34,"lisi"} ,{15,"wanwu"}};
	size_t sz = sizeof(s) / sizeof(s[0]);
    my_qsort(s, sz, sizeof(s[0]), sort_by_name);
	printf("通过名字排序:\n");
	for (int i = 0; i < sz; i++)
	{
		printf("%d   %s\n", s[i].age, s[i].name);
	}
	printf("\n\n");
	printf("通过年纪排序:\n");
	my_qsort(s, sz, sizeof(s[0]), sort_by_age);
	for (int i = 0; i < sz; i++)
	{
		printf("%d   %s\n", s[i].age, s[i].name);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值