【脚踢数据结构】常见排序算法

  • (꒪ꇴ꒪ ),Hello我是祐言QAQ
  • 我的博客主页:C/C++语言,Linux基础,ARM开发板,软件配置等领域博主🌍
  • 快上🚘,一起学习,让我们成为一个强大的攻城狮!
  • 送给自己和读者的一句鸡汤🤔:集中起来的意志可以击穿顽石!
  • 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏

        当谈到排序算法时,计算机科学中有许多经典的排序算法,每种算法都有其独特的原理和特点。下面我将为您介绍一些常见的排序算法,包括它们的原理和代码实现。

一、算法的稳定性

         算法的稳定性指的是在排序过程中,相等元素的相对位置是否保持不变。如果算法是稳定的,那么相等元素在排序后的顺序与它们在原始序列中的顺序相同。稳定性在某些应用中非常重要,例如需要按多个条件排序时。

排序方法平均情况最好情况  最坏情况辅助空间稳定性
冒泡排序O(n^2)O(n)  O(n^2)O(1)稳定
简单选择排序O(n^2)O(n^2)O(n^2)O(1)稳定
直接插入排序O(n^2)O(n)  O(n^2)O(1)稳定
希尔排序O(n log n)~O(n^2)O(n^1.3)O(n^2)O(1)不稳定
堆排序O(n log n)O(n log n)O(n log n)O(1)不稳定
归并排序O(n log n)O(n log n)O(n log n)O(n)稳定
快速排序  O(n log n)O(n log n)O(n^2)O(log n)~O(n)不稳定

        那么不稳定性又是什么呢?

        具体来说,如果在原始序列中,元素 A 和元素 B 相等,且 A 在 B 之前,如果在排序后 A 仍然在 B 之前,那么排序算法就被称为是稳定的;如果排序后 A 和 B 的相对位置发生了改变,那么排序算法就是不稳定的。

        为了更好地理解稳定性和不稳定性,让我们通过一个示例来说明,假设我们有一个待排序的数组,其中每个元素是一个包含姓名和年龄的记录,如下所示:

Name    Age
------------
Alice   25
Bob     30
Carol   25
David   22

        现在我们要按照年龄进行排序,首先考虑使用快速排序,但快速排序是不稳定的排序算法。如果我们使用快速排序对年龄进行排序,可能会得到以下结果:

Name    Age
------------
David   22
Alice   25
Carol   25
Bob     30

        在这个排序后的结果中,虽然 Alice 和 Carol 在原始序列中的相对位置是正确的,但是 Carol 和 David 的相对位置发生了改变,所以快速排序是不稳定的。

        相比之下,如果我们使用稳定的排序算法,如冒泡排序或插入排序,对年龄进行排序,那么无论排序的结果如何,Alice 和 Carol 在排序后的序列中的相对位置仍然保持不变。


二、冒泡排序(Bubble Sort)

         冒泡排序是一种简单的排序算法。它通过多次比较相邻元素的大小并交换位置,使得最大(或最小)的元素逐渐“冒泡”到数组的一端。冒泡排序的时间复杂度为O(n^2),其中n是元素的数量。

         代码实现:

#include <stdio.h>// 交换数组中的两个元素
void swap(int arr[], int i, int j)
{int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}// 冒泡排序
void bubbleSort(int arr[], int n)
{for(int i  = 0 ; i < n ; i ++){for (int j= 0 ; j < n - i -1; j++){if (arr[j] > arr[j+1]){swap(arr , j ,j+1);}}				}}//遍历
void display(int arr[], int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");}int main() {int arr[] = {64, 34, 25, 12, 22, 11, 90, 13, 14, 26, 27, 115, 91, 92, 84, 96, 86, 35, 37, 56, 58, 65, 10, 38, 99 , 105 , 88, 29};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组:\n");display(arr,n);//遍历bubbleSort(arr, n);printf("排序后的数组:\n");display(arr,n);//遍历return 0;
}

三、冒泡排序的改进:鸡尾酒排序

         鸡尾酒排序是对冒泡排序的改进。它通过交替地进行正向和反向的冒泡扫描,从而在每一轮排序中同时处理数组的两端。这样可以更快地将较大和较小的元素分别移到正确的位置。

         代码实现:

#include <stdio.h>
#include <time.h>// 交换数组中的两个元素
void swap(int arr[], int i, int j)
{int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}// 鸡尾酒排序
void cocktailSort(int arr[], int size)
{int left = 0;        // 数组的左边界int right = size - 1;// 数组的右边界while (left < right) // 当左边界小于右边界时继续排序{for (int i = left; i < right; i++) // 从左往右冒泡,将较大的元素往右边“冒”{if (arr[i] > arr[i + 1]){swap(arr, i, i + 1); // 如果相邻元素顺序错误,交换它们}}right--; // 右边界左移,排除已经排好序的元素for (int j = right; j > left; j--) // 从右往左冒泡,将较小的元素往左边“冒”{if (arr[j] < arr[j - 1]){swap(arr, j, j - 1); // 如果相邻元素顺序错误,交换它们}}left++; // 左边界右移,排除已经排好序的元素}
}//遍历
void display(int arr[], int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");}int main()
{int arr[] = {64, 34, 25, 12, 22, 11, 90, 13, 14, 26, 27, 115, 91, 92, 84, 96, 86, 35, 37, 56, 58, 65, 10, 38, 99, 105, 88, 29};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组:\n");display(arr, n);// 获取开始时间clock_t start_time = clock();cocktailSort(arr, n); // 调用鸡尾酒排序函数对数组排序// 获取结束时间clock_t end_time = clock();double total_time = (double)(end_time - start_time) / CLOCKS_PER_SEC;printf("排序后的数组:\n");display(arr, n);printf("运行时间:%f 秒\n", total_time);return 0;
}

四、选择排序(Selection Sort)

         选择排序每次从未排序部分中选择最小(或最大)的元素,然后将其与未排序部分的起始位置交换。选择排序的时间复杂度为O(n^2),其中n是元素的数量。虽然选择排序简单,但在大规模数据上效率较低。

         代码实现:

#include <stdio.h>//交换数组中的两个元素
void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}//选择排序
void selectSort(int arr[], int size) {for (int i = 0; i < size - 1; i++) {int minIndex = i; // 假设当前位置为最小值的索引// 在未排序部分中查找最小值的索引for (int j = i+1; j < size; j++) {if (arr[j] < arr[minIndex]) {minIndex = j; // 更新最小值的索引}}// 如果最小值的索引不等于当前位置,进行交换if (minIndex != i) {swap(&arr[i], &arr[minIndex]); // 将最小值交换到当前位置}}
}

五、插入排序(Insertion Sort)

         插入排序的核心思想是将未排序的元素逐个插入已排序的部分。它通过在已排序部分找到适当位置来插入元素,从而构建有序序列。插入排序的最好情况时间复杂度为O(n),最坏情况为O(n^2)。

        插入排序的理解可以结和玩扑克牌时顺序放牌。

         代码实现:

// 插入排序
void insert_Sort(int arr[], int size) {for (int i = 1; i < size; i++) {int key = arr[i]; // 当前要插入的元素int j = i - 1;//拿到你当前元素的前一个元素的下标// 向前查找插入位置while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j]; // 将比 key 大的元素向后移动一个下标j--;//向前移动元素下标,可以理解为此时比key大的元素已经无需再比较,因此就把它的下标减去}//将key插入到正确位置,即key在当前元素之前arr[j + 1] = key;//为什么是加1,因为此时j值为 -1 加上1 为0,即最数组前方}
}

六、插入排序的更高效改进:希尔排序(Shell Sort)

         希尔排序,也叫递减增量排序,是插入排序的一种更高效的改进版本。希尔排序是不稳定的排序算法。

  希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
  • 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

  希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

  假设有一个很小的数据在一个已按升序排好序的数组的末端。如果用复杂度为O(n^2)的排序(冒泡排序或直接插入排序),可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,所以小数据只需进行少数比较和交换即可到正确位置。

        代码实现:

void ShellSort(int arr[], int n) {int h = 0;// 生成初始增量序列while (h <= n) {h = 3 * h + 1;}// 开始希尔排序while (h >= 1) {// 对每个增量间隔进行插入排序for (int i = h; i < n; i++) {int j = i - h;int get = arr[i];// 插入排序部分while (j >= 0 && arr[j] > get) {arr[j + h] = arr[j];j = j - h;}arr[j + h] = get; // 将当前元素插入正确的位置}h = (h - 1) / 3; // 递减增量序列}
}

七、快速排序(Quick Sort)

         快速排序是一种高效的分治排序算法。它选择一个元素作为“基准”,将数组分成两部分,一部分小于基准,一部分大于基准。然后递归地对两部分进行排序。快速排序的平均时间复杂度为O(n log n),但在最坏情况下可能达到O(n^2)。它通常比其他简单的排序算法更快,并且在实践中效果良好。

        代码实现:

void QuickSort(int arr[], int left, int right) {// 边界条件:如果左边界大于等于右边界,直接返回if (left >= right) {return;}// 选取基准值int i = left, j = right;int pivot = arr[right]; // 以右边值作为基准while (i < j) {// 从左往右找第一个大于等于基准的元素while (i < j && arr[i] < pivot) {i++;}if (i < j) {arr[j] = arr[i]; // 将找到的大于等于基准的元素移到右边j--;}// 从右往左找第一个小于等于基准的元素while (i < j && arr[j] > pivot) {j--;}if (i < j) {arr[i] = arr[j]; // 将找到的小于等于基准的元素移到左边i++;}}arr[j] = pivot; // 基准值归位// 对基准值左边的子数组进行快速排序QuickSort(arr, left, i - 1);// 对基准值右边的子数组进行快速排序QuickSort(arr, i + 1, right);
}

        更多C语言Linux系统ARM板实战数据结构相关文章,关注专栏:

   手撕C语言

            玩转linux

                    脚踢数据结构

                            6818(ARM)开发板实战

📢写在最后

  • 今天的分享就到这啦~
  • 觉得博主写的还不错的烦劳 一键三连喔~
  • 🎉感谢关注🎉

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

让你专注于工作的电脑桌面日程提醒软件

在现代职场中&#xff0c;上班族们常常在繁忙的工作中会遇到各种各样的事情干扰。比如&#xff0c;当我们专注于完成重要的报告时&#xff0c;却又有同事来询问问题&#xff1b;在准备去会议事项时&#xff0c;手机却突然收到了一系列的短信和通知。这些干扰不仅浪费了我们的时…

寄存柜让物品存储变得更简单

寄存柜是一种提供临时性物品寄存服务的设备&#xff0c;通常用于超市、商场、机场、火车站、学校、影院、体育馆等公共场所为用户提供便捷的寄存服务。 寄存柜的种类&#xff1a; 1.行李寄存柜&#xff1a;专门用于旅行者寄存行李和物品的柜子&#xff0c;通常位于机场、火车站…

每天一道leetcode:127. 单词接龙(图论困难建图广度优先遍历)

今日份题目&#xff1a; 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk&#xff1a; 每一对相邻的单词只差一个字母。 对于 1 < i < k 时&#xff0c;每个 si 都在 wordList 中…

PSP - 开源可训练的蛋白质结构预测框架 OpenFold 的环境配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132334671 Paper: OpenFold: Retraining AlphaFold2 yields new insights into its learning mechanisms and capacity for generalization Open…

在思科(Cisco)设备上配置 DHCP 服务器

DHCP广泛用于LAN环境中&#xff0c;从集中式服务器动态分配主机IP地址&#xff0c;从而显着减少IP地址管理的开销。DHCP 还有助于节省有限的 IP 地址空间&#xff0c;因为不再需要将 IP 地址永久分配给主机&#xff0c;只有连接到网络的主机才会使用 IP 地址。DHCP 服务器将路由…

“维度削减+逻辑回归”:如何使用PCA大幅提升乳腺癌的预测成功率?

一、引言 乳腺癌是女性中最常见的恶性肿瘤之一&#xff0c;也影响着全球范围内许多人们的健康。据世界卫生组织&#xff08;WHO&#xff09;的数据&#xff0c;乳腺癌是全球癌症发病率和死亡率最高的肿瘤之一&#xff0c;其对个体和社会的危害不可忽视。因此&#xff0c;早期乳…

ShowMeBug CEO李亚飞受邀参加深圳青年创新创业系列沙龙电子信息专场

7月13日下午&#xff0c;由深圳市科技交流服务中心&#xff08;深圳市科技专家委员会办公室&#xff09;主办&#xff0c;深圳新一代产业园承办的“2023深圳青年创新创业系列沙龙——电子信息专场”活动举行。ShowMeBug CEO李亚飞受邀参加此次活动。 深圳市科学技术协会党组成员…

pdf格式文件下载不预览,云存储的跨域解决

需求背景 后端接口中返回的是pdf文件路径比如&#xff1a; pdf文件路径 &#xff08;https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf&#xff09; 前端适配是这样的 <ahref"https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf&…

【仿写tomcat】二、扫描java文件,获取带有@WebServlet注解的类

tomcat仿写 项目结构扫描文件servlet注解map容器servlet工具类启动类调用 项目结构 扫描文件之前当然要确定一下项目结构了&#xff0c;我这里的方案是tomcat和项目同级 项目的话就仿照我们平时使用的结构就好了&#xff0c;我们规定所有的静态资源文件都在webApp目录下存放…

qiiuzhiji4

本篇是从慧与离职后到2023年8月21日这段时间的经历 2023/7/31至2023/8/21 本篇初次写于2023年8月21日 从慧与离职后基本上就是在专心找工作了&#xff0c;但是有在这段时间找工作经历的人都明白&#xff0c;IT行业不复以往了。尤其是对于我这样的普通二本学历的人来说&#xff…

Ubuntu系统下搭建QtCreator开发环境详细过程(Qt简介;Linux下安装QtCreator)

关于Qt的相关介绍&#xff0c;可以参考QT从入门到实战x篇&#xff0c;Qt 5.9 C开发指南&#xff0c;对于重复部分&#xff0c;本栏目不做详细介绍。关于Linux的基础&#xff0c;本人将重新整理一个栏目&#xff0c;就叫Linux基础吧&#xff0c;有需要的可以后期关注下。 文章目…

发布python模仿2023年全国职业的移动应用开发赛项样式开发的开源的新闻api,以及安卓接入案例代码

python模仿2023年全国职业的移动应用开发赛项样式开发的开源的新闻api&#xff0c;以及原生安卓接入案例代码案例 源码地址:keyxh/newsapi: python模仿2023年全国职业的移动应用开发赛项样式开发的开源的新闻api&#xff0c;以及安卓接入案例代码 (github.com) 目录 1.环境配…

Fast DDS (2)

1、结构&#xff1a; Fast DDS的架构如下图所示&#xff0c;可以看到以下不同环境的层模型&#xff1a; 应用层&#xff1a;利用Fast DDS API 在分布式系统中实现通信的用户应用程序。Fast DDS层&#xff1a;DDS 通信中间件的稳健实现。它允许部署一个或多个 DDS 域&#xff…

leetcode303. 区域和检索 - 数组不可变(java)

前缀和数组的应用 区域和检索 - 数组不可变题目描述前缀和数组代码演示 区域和检索 - 数组不可变 难度 - 简单 原题链接 - 区域和检索 - 数组不可变 题目描述 给定一个整数数组 nums&#xff0c;处理以下类型的多个查询: 计算索引 left 和 right &#xff08;包含 left 和 righ…

Python支持下最新Noah-MP陆面模式站点、区域模拟及可视化分析技术教程

详情点击公众号链接&#xff1a;Python支持下最新Noah-MP陆面模式站点、区域模拟及可视化分析技术教程 Noah-MP 5.0模型&模型所需环境的搭建 陆面过程的主要研究内容&#xff08;陆表能量平衡、水循环、碳循环等&#xff09;&#xff0c;陆面过程研究的重要性。 图 1 陆面…

MySQL语法及常用数据类型

一、SQL语言概述 对数据库进行查询和修改操作的语言叫做SQL。SQL的含义就是结构化查询语言&#xff08;Structured Query Language&#xff09;。SQL包含以下4个部分&#xff1a; 1、数据定义语言&#xff08;DDL&#xff09;&#xff1a;DROP、CREATE、ALTER等语句&#xff…

jenkins 日志输出显示时间戳的方式

网上很多方式比较片面&#xff0c;最新版插件直接使用即可无需更多操作。 使用方式如下&#xff1a; 1.安装插件 Timestamper 2.更新全局设置 系统设置-找到 Timestamper 勾选 Enabled for all Pipeline builds 也可修改时间戳格式。 帮助信息中显示 When checked, timesta…

ARM--day5(C语言点灯实验、总线、串口通信信息、串口通讯协议)

函数分装实现点灯 gpio.c: #include "gpio.h" //函数功能&#xff1a;GPIO引脚初始化操作 //参数1&#xff1a;GPIO组号 //参数2&#xff1a;引脚编号 //参数3&#xff1a;初始化内容 void hal_gpio_init(volatile gpio_t*gpiox,unsigned int pin,gpio_init_t* ini…

rabbitmq的死信队列

目录 成为死信的条件 消息TTL过期 队列达到最大长度 消息被拒 延迟队列 延迟队列使用场景 消息设置 TTL 队列设置 TTL 两者区别 producer 将消息投递到 broker 或者直接到 queue 里了&#xff0c; consumer 从 queue 取出消息 进行消费&#xff0c;但某些时候由…

最新Win10离线安装.NET Framework 3.5的方法(附离线包2022/3/22)

win10系统安装软件时&#xff0c;可能需要.net framework3.5的运行环境&#xff0c;当我们安装某些软件的时候会提示“你的电脑上的应用需要使用以下Windows功能:.NET Framework 3.5(包括.NET 2.0和3.0)。如果系统默认的是4.0以上的版本&#xff0c;当软件需要.net framework3.…