使用冒泡排序模拟实现qsort函数

1.冒泡排序

复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	int arr[] = { 0,2,5,3,4,8,9,7,6,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//冒泡排序一共排序 sz-1 趟
	for (int i = 0; i < sz - 1; ++i)
	{
		//标志位,如果有序,直接退出
		int flag = 0;
		//第一趟比较sz-1次,
		//以后每趟比较次数-1
		for (int j = 0; j < sz - 1 - i; ++j)
		{
			if (arr[j] > arr[j + 1])
			{
				flag = 1;
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
		if (!flag)
			break;
	}
	for (int i = 0; i < sz; ++i)
		printf("%d ", arr[i]);
	return 0;
}

2.模拟实现

2.1认清障碍

qsort函数可以实现任意数据的排序

但此时的冒泡排序不行,阻碍点:

(1)

冒泡排序中if条件判断中的 >

注定了该算法不能实现其他数据的比较

想到:

模仿qsort函数,在冒泡排序内部

调用相关函数实现数据比较

然后根据调用函数的返回值进行后续操作

(2)

上面的交换方式也受到了限制

想到:

需要实现一个

可以实现数据交换的函数

2.2克服障碍

2.2.1依葫芦画瓢

那就依葫芦画瓢,写下声明

复制代码
void Bubble_sort(void*base,size_t num,size_t width,int(*cmp)(const void*p1,const void*p2));

此时:

从左往右,要传入的

第一个参数是待排序数组的第一个元素的地址

第二个参数是 元素个数

第三个参数是 每个元素的大小,单位是字节

第四个参数是 一个函数指针

Bubble_sort函数通过这个函数指针调用相关的函数

被调用的函数就是用来实现任意数据的比较方式的

被调用的函数:

返回值为int,形参为(const void*p1,const void*p2)

(1

p1指向一个数组元素

p2指向的是p1指向的元素之后的第一个元素

(2)函数内部的要求:

(2.1)void*不能直接解引用或+-整数操作

所以需要根据需求进行相应的显式类型转换

(2.2)显示类型转换后,

当p1指向的内容大于p2时,函数返回 大于0的值

当p1指向的内容小于p2时,函数返回 大于0的值

当p1指向的内容等于p2时,函数返回 0

2.2.2逐步实现

复制代码
void Bubble_sort(void*base,size_t num,size_t width,int(*cmp)(const void*p1,const void*p2))
{
	for (int i = 0; i < num - 1; ++i)
	{
		int flag = 0;
		for (int j = 0; j < num - 1 - i; ++j)
		{
			if()
			{

			}
		}
		if (!flag)
			break;
	}
}

冒牌排序外壳:

趟数、比较次数不用改变

2.2.2.1条件判断

if 语句中,根据函数调用返回值进行判断

假设,当当p1指向的内容大于p2时,才进行数据的交换

那么,代码如下:

复制代码
void Bubble_sort(void*base,size_t num,size_t width,int(*cmp)(const void*p1,const void*p2))
{
	for (int i = 0; i < num - 1; ++i)
	{
		int flag = 0;
		for (int j = 0; j < num - 1 - i; ++j)
		{
			if(cmp((char*)base+j*width,(char*)base+(j+1)*width)>0)
			{
                 flag = 1;
                     ..
			}
		}
		if (!flag)
			break;
	}
}

详细解释:

(1)绿色方框框起来的意思是

(1.1)这是两个实参

(1.2)指针指向一种数据时,

总是指向该数据所占空间地址最小的那个字节

(1.3)base接收了数组首元素的地址,但是

我并不知道这是整型、浮点型、字符型的数组

所以我将它强制转换为(char*)类型的指针

这样,无论如何

(char*)base 都指向了数组首元素的第一个字节

(1.4)函数传参传进了width,

注意到:

如果是一个int型的数组

(char*)base 指向了数组首元素第一个字节

(char*)base+width 指向了数组第二个元素第一个字节

(char*)base+2*width 指向了数组第三个元素的第一个字节

如果是一个char型的数组

(char*)base 指向了数组首元素

(char*)base+width 指向了数组第二个元素

(char*)base+2*width 指向了数组第三个元素

所以:

实参就是

复制代码
((char*)base+j*width,(char*)base+(j+1)*width)

(2)橙色方框框起来的意思是

调用cmp函数

(3)红色方框框起来的意思是

当cmp函数返回值>0时,才进行后续的操作

2.2.2.2交换方式

避免代码冗余,创建一个Swap函数进行数据的交换

复制代码
void Bubble_sort(void*base,size_t num,size_t width,int(*cmp)(const void*p1,const void*p2))
{
    for (int i = 0; i < num - 1; ++i)
    {
        int flag = 0;
        for (int j = 0; j < num - 1 - i; ++j)
        {
            if(cmp((char*)base+j*width,(char*)base+(j+1)*width)>0)
            {
                  flag = 1;
                Swap((char*)base+j*width,(char*)base+(j+1)*width, width);
            }
        }
        if (!flag)
            break;
    }
}

(1)我们并不知道元素的类型

但是因为我们知道元素的大小

所以我们可以逐字节地交换两个元素

(2)此时,传入的参数应该是

两个元素的第一个字节、元素的大小

复制代码
 Swap((char*)base+j*width,(char*)base+(j+1)*width, width);

内部实现:

复制代码
void Swap(char* p1, char* p2, size_t width)
{
	for (int i = 0; i < width; ++i)
	{
		 char temp = *p1;
		*p1 = *p2;
		*p2 = temp;

		p1++;
		p2++;
	}
}

(1)width有多大,就交换几次

每次交换后,指针偏移

2.3测试

使用Bubble_sort函数与使用qsort函数一样

需要自己编写一个实现数据比较地函数
这是整型数据的比较


这是字符间的排序 :

注意,元素个数用strlen求!


这是字符串间的排序:

相关推荐
猫猫的小茶馆26 分钟前
【STM32】预分频因子(Prescaler)和重装载值(Reload Value)
c语言·stm32·单片机·嵌入式硬件·mcu·51单片机
JeffersonZU28 分钟前
Linux/Unix文件IO(文件描述符、原子操作、文件数据结构、open、read、write、fcntl、dup)
linux·c语言·unix·gnu
智者知已应修善业4 小时前
【51单片机用数码管显示流水灯的种类是按钮控制数码管加一和流水灯】2022-6-14
c语言·经验分享·笔记·单片机·嵌入式硬件·51单片机
森焱森14 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
小林C语言16 小时前
C语言 | 判断是否为回文数
c语言
myloveasuka19 小时前
信号操作集函数
linux·运维·服务器·c语言·c++·vscode
Mr_Xuhhh20 小时前
网络基础(1)
c语言·开发语言·网络·c++·qt·算法
双叶83611 天前
(C语言)Map数组的实现(数据结构)(链表)(指针)
c语言·数据结构·c++·算法·链表·哈希算法
不会kao代码的小白11 天前
C指针总结复习(结合deepseek)
c语言
XiaoCCCcCCccCcccC11 天前
C语言数组介绍 -- 一维数组和二维数组的创建、初始化、下标、遍历、存储,C99 变长数组
c语言·数据结构·算法