【C语言进阶】模拟库函数qsort的实现(冒泡实现)

文章介绍了冒泡排序的基本原理和代码实现,然后讲解了C语言库函数qsort的使用,强调了其能处理多种类型数据的排序能力,并通过函数指针定义了cmp_int比较函数。接着,自定义了一个bubble_sort函数,模仿qsort的参数设计,实现了通用的排序功能。最后,文章提供了Swap交换函数的实现,用于在排序过程中交换元素。

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

目录

前言

冒泡排序算法

库函数qsort函数

自定义bubble_sort排序函数

test()测试函数

bubble_sort自定义冒泡函数

cmp_int比较函数

Swap()交换函数


前言

我们前边学习了指针的一些高端操作,学会了函数指针的用法,我们今天的任务就是来通过函数指针来模拟库函数qsort的实现。

冒泡排序算法

冒泡排序是一种较为基础的排序算法,它通过相邻元素的比较来实现排序,但是冒泡排序的缺点就是只能进行整型元素的排序,这一点也是一个限制条件。

冒泡排序代码:

void bubble_sort(int arr[], int sz)
{
	//趟数
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		//一趟冒泡排序的过程
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
 

通过给函数传入要排序的整型数组和数组的长度就可以实现对整型元素的排序。

库函数qsort函数

我们刚提到冒泡排序的限制条件是不能对整型以外的数据进行排序,那么有没有其他排序方式呢?答案是有的,C语言的stdlib库中为我们提供了qsort函数(内部是快速排序),我们来讲解一下qsort函数的使用方法。

 

 在对qsort函数的解释中,我们可以看到,它需要四个参数,

第一个参数指向要排序的数组的第一个对象的指针,转换为 void*

第二个参数数组中由 指向的元素数,是无符号整型,unsigned int,size_t

第三个参数数组中每个元素的大小(以字节为单位),是无符号整型,size_t

第四个参数指向比较两个元素的函数的指针,重复调用此函数以比较两个元素。它应遵循以下原型:int (*compar)(const void*,const void*)

第四个参数就是我们最近学习的函数指针,那么此时我们就需要定义一个函数,返回值为int型,通过这个函数,就可以实现多种类型数据的排序。

将两个指针作为参数(都转换为常量 void*)。该函数通过返回(以稳定和传递的方式)来定义元素的顺序:

返回值意义
<0指向的元素 在指向的元素之前p1p2
0指向的元素等效于p1p2
>0指向的元素在指向的元素之后p1p2

qsort库函数代码:

//实现一个比较整型的函数
int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
void test()
{
	
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//bubble_sort(arr, sz);
	//库函数中一个排序函数:qsort
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	test();
	return 0;
}

自定义bubble_sort排序函数

在冒泡排序和qsort库函数排序的基础上,我们就可以自定义一个函数来实现多类型数据的排序。

test()测试函数

首先,我们定义test()函数,将数组的定义以及数组排序后打印放在这个函数中,然后调用我们自定义的排序函数。

//使用我们自己写的bubble_sort函数排序整型数组
void test()
{
	int arr[] = { 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]);
	}
}
int main() {
	test();
	return 0;
}

bubble_sort自定义冒泡函数

我们自定义的bubble_sort函数也有四个参数,与库函数qsort函数的参数是相同的,接下来实现bybble_sort函数

void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* e1, const void* e2))
{
	//趟数
	size_t i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		//一趟冒泡排序的过程
		size_t j = 0;
		for (j = 0; j < sz - 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);
			}
		}
	}
}

由于base是void*类型的指针,但是void*类型不能进行后续的操作,所以我们强制类型转换成char* ,由于char类型元素占一个字节,当我们要找到下一个元素进行比较时,就得用我们所需元素的字节数width*j来找到下一个元素。

cmp_int比较函数

这时我们就通过函数指针来调用cmp函数,这样的好处时我们可以定义多个cmp函数,例如cmp_int,cmp_float,cmp_char,就可以实现多种类型数据的排序。

//实现一个比较整型的函数
int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}

Swap()交换函数

最后再实现交换函数Swap,由于参数是char*,解引用后为char类型,所以进行一个字节一个字节交换,在数据与数据交换之后,buf1和buf2向后移动,交换width次,如果是整型,在32位平台下是四个字节,一次交换一个字节的内容,四个字节就交换四次。

void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}

<think>好的,我现在需要帮助用户找到如何在不使用库函数的情况下实现冒泡排序的示例代码。首先,我得回忆一下冒泡排序的基本原理。冒泡排序通过重复地遍历待排序的列表,比较相邻的元素,如果顺序错误就交换它们,直到没有需要交换的元素为止。这样每次遍历都会将最大的元素“冒泡”到末尾。 用户特别提到不要依赖库函数,所以代码需要完全自己实现排序逻辑。常见的编程语言中,用户可能使用的是C、Python或者Java?但根据用户提供的引用中提到了C语言和易语言,尤其是引用[1]和[4]中的C语言代码,可能用户更倾向于C语言的示例。不过引用[3]提到了高级冒泡排序,但用户的问题还是基础的实现。再看用户的问题,引用的示例代码是Python的快速排序,但用户的需求是冒泡排序,因此可能需要用C语言或者其他语言的例子。 不过,用户现在的问题可能更希望得到一个通用的实现,而引用[1]中的C语言示例可能已经给出了部分代码,但用户可能想要更完整的示例。我需要确认用户需要的语言,但根据引用,可能C语言更合适。不过用户示例中的代码是Python,所以可能用户接受多种语言。但根据引用[4]中的qsort对比,用户可能在用C语言,所以优先考虑C语言的示例。 接下来,我需要确保代码不使用任何库函数,比如在C语言中,qsort是库函数,但用户想要自己实现冒泡排序。所以代码应该包括循环嵌套,比较相邻元素,交换操作。例如,对于数组的排序,使用两层循环,外层控制遍历次数,内层进行相邻比较和交换。 此外,用户可能还需要解释代码的步骤,确保结构清晰。比如,外层循环次数为n-1次,内层循环每次减少已经排序好的元素。交换的时候使用临时变量。 然后检查引用的内容,引用[1]中有C语言冒泡排序函数,但用户可能希望更详细的解释。引用[3]提到高级冒泡排序,但用户需要基础版本。引用[4]对比了冒泡qsort,但用户不使用库函数,所以冒泡实现需要独立。 因此,我需要编写一个C语言冒泡排序示例,不使用任何库函数,除了基本的输入输出可能需要包含stdio.h,但排序函数本身不依赖其他库。例如: void bubble_sort(int arr[], int n) { for (int i = 0; i < n-1; i++) { for (int j = 0; j < n-i-1; j++) { if (arr[j] > arr[j+1]) { int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } } 然后可能需要一个测试例子,比如主函数中初始化数组,调用排序函数,然后打印结果。 同时,需要解释代码的每一步,比如外层循环次数,内层循环处理未排序部分,交换元素的条件等。另外,可能需要说明冒泡排序的时间复杂度,以及优化方法,比如提前终止如果某次遍历没有交换发生,但用户可能不需要优化,只是基础实现。 另外,引用[3]提到无法对字符串或结构体排序,但用户问题可能只需要整数排序,所以暂时不需要处理更复杂的数据类型。 最后,生成相关问题,可能涉及优化、应用场景、性能分析等,如用户示例中的快速排序问题结构。需要确保问题相关但不过于复杂。 总结,步骤是:解释冒泡原理,给出C语言代码示例,详细解释代码步骤,并生成相关问题。</think>### 不使用库函数实现冒泡排序的方法 冒泡排序的核心思想是通过**相邻元素比较与交换**,将最大值逐步“冒泡”到数组末尾。以下是实现步骤和示例代码: --- #### 实现步骤 1. **外层循环控制遍历次数**:若数组长度为$n$,则需要$n-1$次遍历(每次遍历确定一个最大值的位置)。 2. **内层循环处理未排序部分**:每次遍历时,比较相邻元素,若顺序错误则交换。 3. **优化标志**(可选):若某次遍历未发生交换,说明数组已有序,可提前终止排序[^3]。 --- #### 示例代码(C语言) ```c #include <stdio.h> void bubble_sort(int arr[], int n) { for (int i = 0; i < n-1; i++) { // 外层循环:n-1次遍历 int swapped = 0; // 优化标志(可选) for (int j = 0; j < n-i-1; j++) { // 内层循环:处理未排序部分 if (arr[j] > arr[j+1]) { // 比较相邻元素 // 交换元素 int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; swapped = 1; } } if (!swapped) break; // 提前终止(优化) } } int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); bubble_sort(arr, n); printf("排序结果:"); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } return 0; } ``` --- #### 代码解析 - **时间复杂度**:平均和最坏情况为$O(n^2)$,最好情况(已有序)为$O(n)$[^2]。 - **空间复杂度**:$O(1)$(原地排序)。 - **适用场景**:小规模数据或对稳定性有要求的场景[^4]。 ---
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清扰077

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值