【C语言】冒泡排序的快排模拟

news2024/11/29 8:47:35

说到排序,必然绕不开两个排序,冒泡排序快速排序
冒泡排序是大多数人的启蒙排序,因为他的算法简单。但效率不高,便于新手理解;
而快速排序是集大成之作,效率最高,使用最为广泛。

今天这篇文章带来如何使用qsort(quick sort,快速排序),和如何使用冒泡排序的快速排序的模拟。
也会在不久后讲解几大排序的算法。

目录

  • 冒泡排序:
  • qsort的参数设计:
  • 冒泡排序的快排模拟:

冒泡排序:

开始之前先来回顾一下冒泡排序的实现

冒泡排序的思想是让数组的元素从头开始两两比较,大的放在后边(根据情况定),解决完一个元素在进行下一个,如下图。

在这里插入图片描述
从上图中我们发现排序第一趟要进行5次(len-1次)
而一趟可以解决1个元素的位置(当剩最后一个元素时不用排序)
所以可以得到一共需要进行5趟(len-1趟)
故可以写一个外层for循环模拟趟数,循环变量为i,从0开始
在这里插入图片描述
第二次时就进行4
每趟都会减少一个需要排序的元素,与外层循环变量i有关
故我们控制一趟次数的内循环可以根据i来写出适当的表达式

代码实现:

void bubble_sort(int arr[], int len)
{
	for (int i = 0; i < len-1; i++)
	{
		for (int j = 0; j < len - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			//交换
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int len = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, len);
	for (int i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

这样一个朴实无华的冒泡排序就完成了。
接下来研究qsort

一一一一一一一一一分割线一一一一一一一一

qsort的参数设计:

登录网站cpulsplus.com,可以查询qsort函数信息

cpp网站链接
在这里插入图片描述
觉得难以理解不要紧,下边有详细的解释。

我们发现qsort有4个参数

void qsort (void* base, 
            size_t num, 
            size_t size,
            int (*compar)(const void*,const void*));
参数:

1.void*base
大家看到这个肯定就懵了,啥是void*
void*也是一种指针类型,不过他可以接收任意类型的数据;
什么?任意类型,这也就说明qsort不只可以排序整形,字符,甚至结构体都可以排序
base就是数组的数组名,因为知道数组在哪里才可以进行排序。

2.size_t num
size_tsizeof这个操作符的返回值类型,本质是unsigned类型。
num是指数组中元素个数的多少

3.size_t size
排序有了数组名,有了个数就可以排序了吗?
想到冒泡排序好像就是这样,但是,别忘记qsort可以排序任意类型,这也就意味着我们不仅需要知道数组名与元素个数,还需要知道排序的是什么类型,也就是多少字节,size就是数组中每个元素的字节大小。

4.int (*compar)(const void*,const void*))
仔细看,发现他像什么?
没错是个函数指针,他的类型是int (*)(const void*,const void*)),为什么qsort需要传参一个函数指针,因为qsort需要知道两个数据间是如何比较,这取决于使用者的想法,比如结构体你想按照其中的字符串比较还是整形比较

这是比较函数的返回值:
在这里插入图片描述
当返回值小于0 ,p1指向元素被排在p2指向元素左边。即[*p1, *p2];

当返回值大于0 ,p1指向元素被排在p2指向元素右边。即[*p2, *p1];

当返回值等于0 ,p1指向元素和p2指向元素顺序不确定。

即e1指向的值大于e2指向的值,返回正数,否则返回负数,相等时返回0(默认升序)
知道了参数是什么,那我们应该怎样使用呢?
不要看着感觉复杂,其实很简单

#include <stdio.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void * p1, const void * p2)
{
    return (*( int *)p1 - *(int *) p2);
    //因为我们比较的是int类型,所以需要将e1,e2强转后再解引用
    //void*类型是不可以解引用的
}
//注意比较函数的返回值
e1>e2返回一个正数
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    int i = 0;
    qsort(arr, 
          //数组名
          sizeof(arr) / sizeof(arr[0]), 
          //数组的元素个数
          sizeof (int),
          //每个元素类型
          int_cmp);
          //比较函数
    for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
    {
        printf( "%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

这就实现了如何使用qsort。

一一一一一一一一一分割线一一一一一一一一

冒泡排序的快排模拟:

那么如果我们将qsort中的参数放到冒泡排序中,该如何以qsort的方式实现冒泡排序呢?
我们发现,整体的逻辑不需要改动,需要改动的是两个元素的比较需要使用我们自己定义的cmp函数
那么请看代码,会在代码中解释大家的各种疑问
代码实现:

先来看函数的主体部分:,只是改写了参数

int main()
{
	int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1 ,0};
	int len = sizeof(arr) / sizeof(arr[0]);
	//参数改成qsort形式的参数
	bubble_sort(arr, len, sizeof(arr[0]), cmp);
	for (int i = 0; i < len; i++) 
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

然后看冒泡排序的实现:

//比较函数
int cmp(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}

void bubble_sort(void*base,int len,int width,int(*cmp)())
{
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - 1 - i; j++)
		{
		if (cmp((char*)base+width*j, (char*)base + width * (j+1))> 0)
//因为base是void*类型,需要强转成(char*),因为char*是最小的单位,
//容易操作,同时利用width和j得出当前元素与下一个元素的地址,
//在cmp中强转为int*进行比较
//当返回值为正数1说明e1指向的数大于e2指向的,需要交换
			{
				swap((char*)base + width * j, width);
				//交换函数
			}
		}
	}
}

交换函数:
共循环width次,因为width为字节大小,而我们是char*类型,只有1字节,我们通过for循环来交换

void swap(char* p,int width)
{
	for (int i = 0; i < width; i++)
	{
		char tmp = *(p+i);
		*(p+i) = *(p + i + width);
		*(p + i + width) = tmp;
	}
}

在这里插入图片描述
一一一一一一一一一分割线一一一一一一一一
整体代码:

int cmp(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}
void swap(char* p,int width)
{
	for (int i = 0; i < width; i++)
	{
		char tmp = *(p+i);
		*(p+i) = *(p + i + width);
		*(p + i + width) = tmp;
	}
}
void bubble_sort(void*base,int len,int width,int(*cmp)())
{
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - 1 - i; j++)
		{
			if (cmp((char*)base+width*j, (char*)base + width * (j+1)) > 0)
			{
				swap((char*)base + width * j, width);
			}
		}
	}
}

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

欢迎纠错与交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/951794.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ae 效果:CC Glass Wipe

过渡/CC Grid Wipe Transition/CC Grid Wipe CC Glass Wipe&#xff08;CC 玻璃擦除&#xff09;效果用于创建一种基于亮度信息的擦除方式&#xff0c;过渡边缘有类似于玻璃的质感。 ◆ ◆ ◆ 效果属性说明 Completion 完成度 控制过渡效果的完成进度。 值从 0 %&#xff08;…

自动驾驶车辆换道过程建模与分析

目 录 第1 章 绪论 ................................................................................................................. 1 1.1 研究背景及意义.............................................................................................. 1 1.2 研究…

ACM模式数组构建二叉树Go语言实现

目的 想输入一个数组&#xff0c;然后构造二叉树 例如数组为[6, 2, 8, 0, 4, 7, 9, -1, -1, 3, 5] 对应的二叉树为&#xff1a; 参考资料 ACM模式数组构建二叉树 重点&#xff1a;如果父节点的数组下标是i&#xff0c;那么它的左孩子下标就是i*21&#xff0c;右孩子下标就是…

Leetcode 易错题整理(二)40. 45. 46. 47. 49. 56. 62. 63.

40. 组合总和 II 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 **注意&#xff1a;**解集不能包含重复的组合。 示例 1: 输入: candidat…

Doris数据库BE——Stream load

Doris是一款快速、可靠的分布式大数据仓库&#xff0c;是由阿里巴巴集团在2016年底开源发起的。它采用了分布式存储和计算技术&#xff0c;可以处理海量的数据&#xff0c;并且可以实现实时查询和快速分析。 Doris 数据仓库有以下特点&#xff1a; 分布式计算&#xff1a;利用…

结构体(个人学习笔记黑马学习)

1、结构体的定义和使用 #include <iostream> using namespace std; #include <string>struct Student {string name;int age;int score; }s3;int main() {//1、struct Student s1;s1.name "张三";s1.age 18;s1.score 100;cout << "姓名&a…

【阻塞队列】

文章目录 普通队列存在的问题单锁实现双锁实现 普通队列存在的问题 大部分场景要求分离向队列放入&#xff08;生产者&#xff09;、从队列拿出&#xff08;消费者&#xff09;两个角色、它们得由不同的线程来担当&#xff0c;而之前的实现根本没有考虑线程安全问题队列为空&a…

【记录】手机QQ和电脑QQ里的emoji种类有什么差异?

版本 手机 QQ&#xff1a;V 8.9.76.12115 电脑 QQ&#xff1a;QQ9.7.15&#xff08;29157&#xff09; 偶然发现&#xff0c;有一种emoji手机上怎么找都找不到&#xff0c;一开始以为自己失忆了&#xff0c;后来发现这种emoji只在电脑上有。 接下来简单说一下找emoji差异的方式…

912.排序数组

目录 一、题目 二、代码 一、题目 912. 排序数组 - 力扣&#xff08;LeetCode&#xff09; 二、代码 class Solution { public:void _MergeSort(vector<int>&data,vector<int>&tmp,int begin,int end){if(begin>end)return;//结束条件int mid (beg…

解决博客不能解析PHP直接下载源码问题

背景&#xff1a; 在网站设置反向代理后&#xff0c;网站突然不能正常访问&#xff0c;而是会直接下载访问文件的PHP源码 解决办法&#xff1a; 由于在搞完反向代理之后&#xff0c;PHP版本变成了纯静态&#xff0c;所以网站不能正常解析&#xff1b;只需要把PHP版本恢复正常…

记录一些问题

1、如何下载从数据库中查询出来的数据 查询结果List 写到文件中&#xff0c;然后下载 GetMapping(value "/download")public void download(HttpServletResponse response)throws IOException {List<ticket> tickets getTickets();File tmpFile write2CSVF…

Python的os.walk()函数使用案例

在Python中&#xff0c;os模块是一个非常实用的工具&#xff0c;它可以让我们与操作系统进行交互&#xff0c;操作文件和目录。在本文中&#xff0c;我们将详细介绍os模块中的遍历文件功能&#xff0c;并通过具体案例和使用场景来解释。 首先&#xff0c;导入os模块。在Pytho…

嵌入式学习之exec族函数

今天&#xff0c;主要学习的内容是exec族函数和system函数&#xff0c;以及system函数和fork函数的配合使用。今日写的代码如下&#xff1a;

《Kubernetes部署篇:Ubuntu20.04基于containerd部署kubernetes1.24.17集群(多主多从)》

一、架构图 如下图所示: 二、环境信息 1、部署规划主机名K8S版本系统版本内核版本IP地址备注k8s-master-631.24.17Ubuntu 20.04.5 LTS5.15.0-69-generic192.168.1.63master节点 + etcd节点k8s-master-641.24.17Ubuntu 20.04.5 LTS5.15.0-69-generic192.168.1.64master节点 + …

Linux禅道上修改Apache 和 MySQL 默认端口号

1. 修改Apache默认端口号 80 cd /opt/zbox/etc/apachevim httpd.conf :wq 保存 2. 修改MySQL默认端口号 3306 cd /opt/zbox/etc/mysql vim my.cnf :wq 保存 3. 重启服务 ./zbox restart

计算机网络-笔记-第六章-应用层

目录 六、第六章——应用层 1、应用层概述 2、(C/S)客户-服务器方式 & &#xff08;P2P&#xff09;对等方式 &#xff08;1&#xff09;客户-服务器方式【C/S】 &#xff08;2&#xff09;对等方式【P2P】 3、DHCP——动态主机配置协议 &#xff08;1&#xff09;诞…

面试结束后:如何写一封有效的感谢信

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

开源且强大的网络嗅探分析工具——Wireshark

Wireshark是一款强大的开源网络协议分析工具&#xff0c;旨在帮助用户深入了解网络通信的细节。通过捕获、解析和展示网络数据包&#xff0c;Wireshark能够帮助工程师诊断问题、优化性能&#xff0c;以及解决各种网络难题。无论是深入分析还是快速调试&#xff0c;Wireshark都是…

学习pytorch7 神经网络的基本骨架--nn,module的使用

神经网络的基本骨架--nn,module的使用 官网Module介绍Python父类子类继承关系前向神经网络pycharm快捷键重写类方法codedebug B站小土堆视频学习笔记 官网Module介绍 https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module Python父类子类继承关系…

4.4 对幻灯片进行动画制作

动画是演示文稿的重要构成要素&#xff0c;WPS演示为用户提供了多种动画类型&#xff0c;通过学习设置页面切换、动画效果等相关功能&#xff0c;可使演示文稿更加生动&#xff0c;富于表现力。 4.4.1 设置页面的切换方式 页面的切换是指从一张幻灯片切换到另一张幻灯片时的页…