【C语言冒泡排序、选择排序和快速排序】

2023-05-16

文章目录

  • 前言
  • 一、冒泡排序
  • 二、选择排序
  • 三、 快速排序
  • 四、代码设计与实现
    • 代码设计
    • 代码实现
  • 调试结果
    • 冒泡排序改良
  • 延伸思考
  • 总结


前言

本文简单介绍了C语言的冒泡排序、选择排序、快速排序,结合本人的理解与使用做一下记录。


一、冒泡排序

思想:(以小到大排序为例)假设一个数组有n个数,第一轮遍历这个数组的前(n-1)个数,遍历的时候比较当前位置和下一个位置的数,如果当前位置的数比较大,就跟下一个数交换位置;所以第一轮结束之后,就会把最大的数“沉”到数组的末尾位置;第二轮遍历这个数组的前(n-2)个数,按照前面的方法把第二大的数“沉”到数组的倒数第二个位置;依此类推,(n-1)轮之后每一个较大的数都按顺序沉到了数组的相应位置。

二、选择排序

思想:使用for循环对数组进行排序;每循环一次,选择出一个较大的数,然后与
数组中的第n个位置交换数据,n从0开始。假设这个数组有n个数据,那么循环(n-1)次即可完成排序。

三、 快速排序

思想:

  1. 首先确定一个target,找到这个target在数组中的位置;它会把这个数组分割成两部分(你可以认为是两个待排序的区域),并且左边的数都比它小,右边的数都比它大;
  2. 这两个区域都设置了新的target,然后通过递归确定左边这个区域的新target的位置和右边这个区域的新target的位置;继续分割继续递归直到区域的数据只有一个为止;
  3. 最终可以实现数组中的每一个数据的左边的数都比它小且右边的数都比它大,从而完成排序。

四、代码设计与实现

代码设计

编写一个程序,随机生成10个整数并赋值给数组;然后分别使用冒泡排序、选择排序和快速排序对这个数组进行排序并打印出排序后的结果。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>


void BubbleSort(int *a, int length) ;
void select_sort(int *array, int size);
void quick_sort(int *array, int low, int high);

#define SIZE 10
//#define SELECT_SORT
//#define BUBBLE_SORT
#define QUICK_SORT

int main(void)
{
	int array[SIZE];
	int i;
	
	srand(time(0));	//设置随机数种子
	//使用随机数初始化数组
	for(i = 0; i < SIZE; i++)
	{
		array[i] = rand() % (50-3+1)+3;	//生成[3,50]范围内的随机整数
	}
	
	printf("排序之前,数组为:");
	for(i = 0; i < SIZE; i++)
	{
		printf("%d\t", array[i]);
	}
	printf("\n");

#ifdef SELECT_SORT
	//使用选择排序对数组从大到小排序
	select_sort(array, SIZE);
#elif defined BUBBLE_SORT
	//选择冒泡排序对数组从小到大排序
	BubbleSort(array, SIZE);
#else
	//使用快速排序对数组从小到大排序
	quick_sort(array, 0, SIZE-1);
#endif
	printf("排序之后,数组变为:");
	for(i = 0; i < SIZE; i++)
	{
		printf("%d\t", array[i]);
	}
	printf("\n");



	return 0;
}

//冒泡排序
void BubbleSort(int *a, int length) 
{
	int temp;
	for (int i = 0; i < length - 1; i++)
	{
		for (int j = 0; j < length - i - 1; j++)
		{
			if (a[j] > a[j + 1])
			{
				
				temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
			}
		}
	}
}

//选择排序(非稳定版本)
void select_sort(int *array, int size)
{
	int max;
	int pos;
	int i,j;
	int tmp;

	max = array[0];
	pos = 0;
	for(i = 0; i < size-1; i++)	//循环一次就找到一个较大的数,然后与数组的第n个数据交换位置(n从0开始)
	{
		max = array[i];
		pos = i;
		
		for(j = i; j <= size-1; j++)
		{
			if(array[j] > max)
			{
				max = array[j];
				pos = j;
			}
		}
		//交换pos位置与i位置的数据
		tmp = array[i];
	    array[i] = array[pos];
		array[pos] = tmp;
	}
}

//快速排序
void quick_sort(int *array, int low, int high)
{

	if(low < high)
	{
		int i = low;
		int j = high;
		int key = array[low];
		
		while(i < j)	//两个游标重合,即可确定key的位置
		{
			while(i < j && array[j] > key)	//从右往左找,找到一个小于等于key的数据,然后与key交换位置
			{
				j--;
			}
			if(i < j)
			{
				array[i++] = array[j];	//把找到的这个数放到key的位置
			}

			while(i < j && array[i] <= key)	//从左往右找,找到一个大于key的数据,然后与key交换位置
			{
				i++;
			}
			if(i < j)
			{
				array[j--] = array[i];	//把找到的这个数放到key的位置
			}
		}

		array[i] = key;
		
		quick_sort(array, low, i-1);
		quick_sort(array, i+1, high);
	}
}

代码分析:

首先是使用srand函数设置随机数种子,time(0)是用来获取随机数种子;
然后使用rand函数产生随机数,赋值给数组元素;
如果要产生[m,n]范围内的随机数num,可用:

int num=rand()%(n-m+1)+m;

其中的rand()%(n-m+1)+m算是一个公式

上面的代码可以选择冒泡排序、选择排序或者选择快速排序,可以通过宏选择。
我有看过别人写的快速排序,我觉得有些操作是可以优化的;比如交换数据这一步,因为key的位置有可能一直在变,所以没必要每次都把key写到某个位置(过渡位置),只需要确定好最终位置再赋值。

当然,上面这个只是示例代码,还可以再封装、再优化,需要大家再斟酌一下。

调试结果

下图是冒泡排序,对数组从小到大排序

zzc@zzc-virtual-machine:~/share$ ./1
排序之前,数组为:26	43	47	37	22	48	48	8	37	15	
排序之后,数组变为:8	15	22	26	37	37	43	47	48	48

下图是选择排序,对数组从大到小排序

zzc@zzc-virtual-machine:~/share$ ./1
排序之前,数组为:  40   10	31	26	23	48	50	6	30	41	
排序之后,数组变为:50	  48	41	40	31	30	26	23	10	6	

下图是快速排序,对数组从小到大排序

zzc@zzc-virtual-machine:~/share$ ./1
排序之前,数组为:33	30	24	27	23	41	29	9	8	4	
排序之后,数组变为:4	8	9	23	24	27	29	30	33	41	

冒泡排序改良

我们可以对冒泡进行改良,一个数组中的数据可以分为有序数列和无序数列;排序过程中,有序数列处于数组的后半段,不需要再给它排序,只需要对无序数列进行排序。
另外,如果第一轮比较下来发现没有数据交换位置,那就表示整个数组已经排列好了,直接结束排序即可。

按照这个思路,我们来实现一个示例,如下:

//冒泡排序改良版
void BubbleSortNew(int *a, int length) 
{
	int temp;
	//记录最后一次交换的位置
	int last_exchange_index = 0;
	//无序数列的边界,每次比较只需要比到这里	
	int sort_border = length - 1;

	for (int i = 0; i < length - 1; i++)
	{
		bool isSorted = true;
		for (int j = 0; j < sort_border; j++)
		{
			if (a[j] > a[j + 1])
			{
				isSorted = false;	//有数据要交换位置,所以不是有序,标志置为false 
				temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
				last_exchange_index = j;
			}
		}
		sort_border = last_exchange_index;
		if(isSorted)	//一轮下来是否发生数据交换,没有就退出排序
			break;
	}
}

实测对10000个随机数(范围为0到9999)进行排序,在笔者的主机环境中传统的冒泡花费了158237 个cpu clock,而改良版话费了151638 个cpu clock,节省了6599个cpu clock,所以效率上还是有所提高的。

延伸思考

常见算法时间复杂度如下图:
排序算法时间复杂度

1、快速排序虽然效率较高、耗时短,但是一直压栈(数据量很大的时候)很容易造成堆栈溢出
2、排序算法应该尽量避免使用递归。
3、排序算法非常多,应该结合具体的应用场景来选择合适的算法。(从来没有最好的,只有最适合你的)


总结

本文主要介绍了C语言中冒泡排序、选择排序和快速排序的思想,并进行了相应的代码实现和调试。
同时对冒泡排序进行了改良。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C语言冒泡排序、选择排序和快速排序】 的相关文章

  • 基础操作之按键消抖

    机械弹性开关 xff1a 当机械触点断开 闭合时 xff0c 由于机械触点的弹性作用 xff0c 一个按键开关在闭合时不会马上就稳定的接通 xff0c 在断开时也不会一下子彻底断开 xff0c 而是在闭合和断开的瞬间伴随了一连串的抖动 xf
  • 关于无人机的智能吊舱项目的开发小结

    智能吊舱是基于光电吊舱项目之上 xff0c 加入AI的深度学习算法的一种应用 xff1b 在巡检的各类使用将发挥重要作用 xff01 我要实现的操作是 xff1a 我在飞机地面站上预置好飞机的航线航点 xff08 就是飞机需要巡逻的航线和需
  • stm32的LWIP在无操作系统下TCP功能加入双路IP

    1 stm32f207 xff0c 无操作系统 xff0c LWIP 1 3 2 xff0c 开发TCP服务器下的双路ip xff1b 实现前提 xff1a 先调通 xff0c 实现单路IP xff1b 参考帖子 xff08 然而最后的感觉
  • linux 小项目开发-1-概括和start(linux-SPI驱动小结)

    项目的要求 xff1a 环境温度的检测和报警系统 系统介绍 xff1a 实时读取环境温度 读 写IIC接口的EEPROM 控制管显示 按键编程 串口 网口输出数据 LED显示闪烁报警 蜂鸣器响声告警 xff0c 本地GUI显示状态 xff0
  • 【Linux系统获取时间的函数】

    文章目录 前言Linux的API获取时间 time函数 gettimeofday函数 time函数 gettimeofday函数使用代码示例 时间转换 ctime函数 ctime函数使用代码示例 asctime函数 asctime函数使用代
  • docker: invalid reference format.

    不是 的问题的话 xff0c 就是这个问题 今天 xff0c 有一个网友在做毕业设计 xff0c 说是用用 docker xff0c 但是在执行 docker run 的时候 xff0c 报错了 xff0c 提示 docker invali
  • docker build 用法

    在包含Dockerfile 文件的目录下执行 xff1a docker build t nginx v3 即是创建了镜像 docker build 命令进行镜像构建 其格式为 xff1a docker build 选项 lt 上下文路径 U
  • Docker 镜像备份与迁移

    1 容器保存为镜像 docker commit pinyougou nginx mynginx pinyougou nginx 是容器名称 mynginx 是新的镜像名称 2 镜像导出 docker save o dockerdemo ta
  • android T 前台Service

    获取android 13 用户控制 用户在长时间运行的应用程序上获得更多透明度和控制权 xff1a 前台服务仍然需要包含通知 xff0c 并且应用程序必须请求权限才能显示通知 FGS 通知现在可以被用户关闭而不影响 FGS用户可以在任务管理
  • android 8.0+后台Service限制

    后台Service限制 背景 每次在后台运行时 xff0c 应用都会消耗一部分有限的设备资源 xff0c 例如 RAM 这可能会影响用户体验 xff0c 如果用户正在使用占用大量资源的应用 xff08 例如玩游戏或观看视频 xff09 xf
  • CMake入门(一)Ubuntu下使用和Window下使用

    引用一段知乎上关于 xff1a CMake 如何入门 xff1f 生态如此 xff0c 长久来看 xff0c 绕不开 就像Github 看了下 xff1a B站上的一个资源 cmake构建c 43 43 项目快速入门2 1 在Windows
  • 安装ubuntu成功后不能重启(nomodeset)躺坑记录acpi int3400:00:Unsupported event

    针对这篇文章的补充 xff1a 安装ubuntu成功后不能重启 xff08 nomodeset xff09 legalhighhigh的博客 CSDN博客 如果找不到 34 Boot Options ed boot 61 initrd 61
  • npm install 出现错误 unable to access ‘https://github.com/adobe-webplatform/eve.git/‘:

    前言 xff1a 输入命令 npm install registry 61 https registry npm taobao org xff0c 出现错误 unable to access 39 https github com adob
  • Kubernetes初识

    一 Kubernetes是什么 xff1f xff08 一 xff09 读音 了解一个新事物 xff0c 最先学会都是怎么读 xff0c 不然以后会一直读错下去 xff0c 到时候说出去可能就会被人嘲笑 Kubernetes xff0c 读
  • Linux操作系统基本代码

    1 xff08 ls xff09 list 列出目录的所有项 ls 查看当前目录 xff08 ls l 文件路径 xff09 以详细模式查看 xff08 ls xff5e xff09 展示主目录文件 xff08 ls xff09 展示当前目
  • C语言 const、static、volatile等关键字的作用

    目录 前言 const static volatile extern 总结 前言 C语言里面有许多关键字 xff0c 本文结合我自己的了解简单讲讲几个常用关键字的作用 const 问 xff1a const有什么用 xff1f 答 xff1
  • 函数调用,中断以及进程切换,的现场保护的区别

    注意以下过程描述了两种armv7指令集的内核的中断表现 xff08 cortex A7和cortex m3 xff09 xff0c 但是cortex A7和cortex m3表现很不一样 xff0c 因为Cortex m3只有用户级和特权级
  • Cortex-M3 PendSV 中断 系统调用 说明

    参考 Cortex M3权威指南中文版 PendSV异常是和系统调用有些类似 xff0c cpu 需要手动将往NVIC 的PendSV 悬起寄存器中写1 xff0c 然后产生中断 xff0c 系统调用 xff08 SVC xff09 是co

随机推荐

  • 微积分的直观理解

    在微积分中 xff0c 我们进行定积分计算的时候一般是用牛顿莱布尼兹公式 xff0c 不定积分计算也类似 xff0c 都需要寻找原函数F x xff0c 但是如果想直观的理解微积分 xff0c 我们需要顺着公式的反方向进行理解 xff0c
  • Makefile中调用make命令,-C和-f选项的区别

    C选项 Makefile中 C是递归调用子目录中的Makefile xff0c C选项后跟目录 xff0c 表示到子目录下执行子目录的Makefile xff0c 顶层Makefile中的export的变量还有make默认的变量是可以传递给
  • 卡尔曼滤波

    标准卡尔曼滤波推导相关 预测 predict 更新 update 注意 xff0c 以下对于时间的下标 xff0c 有的时候用t有的时候用k xff0c 它们其实是一样的 xff0c 因为参考不同的资料 xff0c 所以写的比较乱 其中是隐
  • EM算法原理

    Notion The all in one workspace for your notes tasks wikis and databases
  • Android ko module compile 简介

    Notion The all in one workspace for your notes tasks wikis and databases
  • volatile c语言关键字 / cache / 内存一致性

    Notion The all in one workspace for your notes tasks wikis and databases
  • Qt中的QWidget::move函数

    QWidget move函数 原型 xff1a void move int x int y void move const QPoint amp 其中move的原点是父窗口的左上角 xff0c 如果没有父窗口 xff0c 则桌面即为父窗口
  • 欧拉角和万向节死锁

    一 什么是欧拉角 欧拉角就是物体绕坐标系三个坐标轴 xff08 x xff0c y xff0c z轴 xff09 的旋转角度 xff0c 在这里坐标系可以是世界坐标系 xff0c 也可以是物体坐标系 xff0c 旋转顺序也是任意的 xff0
  • 【freeRTOS内存管理策略详解】

    内存管理对应用程序和操作系统来说都非常重要 现在很多的程序漏洞和运行崩溃都和内存分配使用错误有关 FreeRTOS操作系统将内核与内存管理分开实现 xff0c 操作系统内核仅规定了必要的内存管理函数原型 xff0c 而不关心这些内存管理函数
  • NGFF、M.2、PCIe、NVMe概念区分以及PCIEx1 x4 x8 x16区别

    对于NGFF M 2 PCIe NVMe等概念的说明 解决方案 NGFF Next Generation Form Factor xff0c 顾名思义 xff0c 是物理外形 Form Factor 的标准 与 NGFF 并列的是 2 5
  • 二重积分和雅可比行列式

    我们以二重积分为例进行说明 xff0c 首先说结论 xff1a 一 结论 若x 61 x u v y 61 y u v 存在偏导数 xff0c 则二阶雅可比行列式为 61 61 dxdy 61 J2 dudv J2的绝对值 且 其中积分区域
  • 雅可比行列式和雅可比矩阵

    接触雅可比行列式是在二重积分的变量变换中 xff0c 参见我的另一篇文章https blog csdn net xiaoyink article details 88432372 下面我们来详细说明一下雅可比行列式和雅可比矩阵 雅可比矩阵
  • jlink-v8 固件修复

    一 先说 jlink v8 v9 v10区别 v8基本价格在40左右 xff0c 芯片是atml的 xff0c 但是很多反应是掉固件和提示盗版问题 v9现在主流 xff0c 盗版价100左右 xff0c 主控芯片stm32 做的比较成熟 x
  • kubernetes学习-快速上手速查手册

    目录 使用k3s快速搭建k8s安装k8s dashboard使用Helm部署K8S资源k8s核心命令一切推倒重来资源创建方式NamespacePodDeploymentServiceIngress解决官网Ingress安装不了问题使用方式
  • 作为一个4年程序员至少需要掌握的专业技能

    一名3年工作经验的程序员应该具备的技能 xff0c 在机缘巧合之中 xff0c 看了这篇博客 感觉自己真的是很差 xff0c 一直想着会写if else 就已经是一名程序员了 xff0c 在工作之余也很少学习 于是 xff0c 自己的cod
  • C语言与C++的区别

    一 C 43 43 简介 本贾尼 斯特劳斯特鲁普 于1979年4月在贝尔实验室负责分析UNIX系统的内核的流量情况 于1979年10月开始着手开发一种新的编程语言 在C语言的基础上增加了面向对象机制 这就是C 43 43 的来历 在1983
  • 我的2011-当梦想照进现实

    我的2011年 xff0c 之所以是现在的样子 xff0c 始缘于我三年前的一个决定 离职考研 对于工作了两年的我来说 xff0c 离职考研是人生的一场博弈 我的2011年 xff0c 结束了研究生期间对三维骨骼动画渲染的相关研究 xff0
  • Dockerfile RUN 同时执行多条命令

    Dockerfile RUN 同时执行多条命令 Dokcerfile中的命令每执行一条即产生一个新的镜像 xff0c 当前命令总是在最新的镜像上执行 如下Dockerfile xff1a RUN span class hljs built
  • HC-SR04超声波模块使用记录

    文章目录 HC SR04超声波模块使用记录轮询测量方式一 模块使用中的问题二 应对方法三 注意 分时测量利用输入捕获测量利用输入捕获测量 HC SR04超声波模块使用记录 具体使用方法见HC SR04使用手册 xff0c 本文重点记录该模块
  • 【C语言冒泡排序、选择排序和快速排序】

    文章目录 前言一 冒泡排序二 选择排序三 快速排序四 代码设计与实现代码设计代码实现 调试结果冒泡排序改良 延伸思考总结 前言 本文简单介绍了C语言的冒泡排序 选择排序 快速排序 xff0c 结合本人的理解与使用做一下记录 一 冒泡排序 思