选择排序,冒泡排序,插入排序,快速排序及其优化

目录

1 选择排序

1.1 原理

1.2 具体步骤 

1.3 代码实现

1.4 优化

2 冒泡排序

2.1 原理

2.2 具体步骤

2.3 代码实现

2.4 优化

3 插入排序

3.1 原理

3.2 具体步骤 

3.3 代码实现

3.4 优化

4. 快速排序 

4.1 原理

4.2 具体步骤

4.3 代码实现 

4.4 优化 


为了讲解方便,以下排完序后,统一为升序

1 选择排序

1.1 原理

核心思想是通过不断地选择未排序序列中的最小元素,然后将其放到已排序序列的末尾(或未排序列的起始位置)

 

1.2 具体步骤 

1. 初始状态:所有元素初始都为未排序状态

2 在未排序元素中,找到最小的那个元素的下标

3 与未排序的第一个元素(已排序的末尾元素)交换位置

4 循环 2 ~ 3,直到所有元素都变为已排了的元素

1.3 代码实现

代码实现的关键点:找下标,换位置,以及循环条件。同时也是容易出错的点。

#include<stdio.h>void sort(int* p, int n)
{for (int i = 0; i < n - 1; i++) // < n 也可以,只是无意义的重复,效率更低{int min = i;   // 找出的最小值,最后要放的位置的下标int j = i;for (j = i + 1; j < n; j++)  // 可以=i,只是=i,无意义。{if (p[min] > p[j])min = j;	//  for循环结束后,j会++  if (n - 1 == j)break;}// 交换数据int temp = p[i];p[i] = p[min];p[min] = temp;}
}int main()
{int arr[] = { 9,6,8,-1,0,5,2,8 };int sz = sizeof(arr) / sizeof(arr[0]);sort(arr, sz);  // 选择排序for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

1.4 优化

 原来一趟只找出最小值,现在一趟既找出最小值,也找出最大值,循环的次数就减半了。

#include<stdio.h>void swap(int* a, int* b)
{int temp = *a;*a = *b;*b = temp;
}void sort(int* p, int n)
{// 循环趟数减半,可以了就要停止,不然就会继续换,反而无序for (int i = 0; i <= n / 2 + 1; i++) {int min = i;   // 找出的最小值的下标int max = n -i - 1; // 找出的最大值的下标int j = i;for (j = i; j < n - i; j++) {if (p[min] > p[j])min = j;if (p[max] < p[j])max = j;if (n - 1 - i == j)break;}// 交换数据// 当最小值与最大值恰好位置相反,换两次=没换if (!(p[min] == p[n - 1 - i] || p[i] == p[max])){swap(&p[i], &p[min]);swap(&p[n - 1 - i], &p[max]);}else{swap(&p[i], &p[n - 1 - i]);}}
}int main()
{int arr[] = { 9,6,8,-1,0,5,2,8 };int sz = sizeof(arr) / sizeof(arr[0]);sort(arr, sz);  // 选择排序优化for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

2 冒泡排序

2.1 原理

核心思想是通过重复交换相邻元素来实现排序。

类比选择排序,相当于从右往左开始排,每次在未排序中找出最大值,放在已排序的前一个位置。

 

2.2 具体步骤

1. 从左往右相邻元素比较,让大的数不断右移

2. 循环1,直至每个已排序的元素 = 所有元素的个数

2.3 代码实现

关键点:循环条件的控制,以及交换(大的靠右)

#include<stdio.h>void sort(int arr[], size_t sz)
{for (int i = 0; i < sz - 1; i++){// 在这里j可以 < sz - 1;// 在本段代码中交换位置是有条件的// < sz - 1;进去了也不会执行// 选择排序从哪开始到哪结束就必须是那样// 不可能在再在排了序中挑最大最小值for (int j = 0; j < sz - 1 - i; j++){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}int main()
{int arr[] = { 9,6,8,-1,0,5,2,8 };size_t sz = sizeof(arr) / sizeof(arr[0]);sort(arr, sz);  // 冒泡排序for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

2.4 优化

如果我们一开始拿到的数组就是有序的话,我们还是不得不执行那循环套循环,效率就很低。我们可以先假设已达到了有序状态,如果交换了,就通过修改flag的值来办,这样就可以提前跳出循环了。

#include<stdio.h>void sort(int arr[], size_t sz)
{for (int i = 0; i < sz - 1; i++){// 假设已经到达了有序状态int flag = 1;for (int j = 0; j < sz - 1 - i; j++){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;// 交换了,说明无序flag = 0;}}if (flag){break;}}
}int main()
{int arr[] = { 9,6,8,-1,0,5,2,8 };size_t sz = sizeof(arr) / sizeof(arr[0]);sort(arr, sz);  // 冒泡排序优化for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

3 插入排序

3.1 原理

核心思想是构建有序序列将未排序的元素逐个插入到已排序的部分。

左边是已排序的,右边是未排序的。未排序的从左到右第一个,放到已排序列中开始交换,大的就右移,移到不能再移。

 

3.2 具体步骤 

1. 初始化:左边第一个是已排序的,右边都是未排序的。

2 交换位置:未排序的第一个进入排序中,比较大小,大的右移,移到不能再移

3 循环 1 ~ 2,直到遍历数组中的所有元素

3.3 代码实现

关键点: 交换位置的意识,递推的意识

#include<stdio.h>void sort(int arr[], size_t sz)
{// 外层每一次循环都会让已排序的元素+1for (int i = 1; i < sz; i++){int j = i;while (j >= 1 && arr[j] < arr[j - 1]){// 交换位置arr[j - 1] = arr[j] ^ arr[j - 1];arr[j] = arr[j] ^ arr[j - 1];arr[j - 1] = arr[j] ^ arr[j - 1];j--;}}
}int main()
{int arr[] = { 9,6,8,-1,0,5,2,8 };size_t sz = sizeof(arr) / sizeof(arr[0]);sort(arr, sz);  // 插入排序for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

3.4 优化

所谓优化算法就更接近于通俗意义上的插入,找到该插入的的地方,再进行插入。即对插入的位置实行二分查找。

#include<stdio.h>// 返回值是该数插入进去后的下标
int find(int arr[], int sz)
{//    1 2 4 5 7 8 9   6int left = 0;int right = sz - 1;while (left < right){// 防止陷入死循环if (left == right)break;int mid = right + (left - right) / 2;if (arr[mid] > arr[sz]){right = mid - 1;}else if (arr[mid] < arr[sz]){left = mid + 1;}else{right = left;break;}}if (arr[sz] < arr[right]){return right;}else{return right + 1;}
}void sort(int arr[], size_t sz)
{for (int i = 1; i < sz; i++){// 本质:二分查找 + 交换int temp = arr[i]; // 将要排序的数暂时储存起来// 二分查找找到应该插入的下标int final_local = find(arr, i);// 该右移的右移for (int j = i - 1; j >= final_local; j--){arr[j + 1] = arr[j];}arr[final_local] = temp;}
}int main()
{int arr[] = { 9,6,8,-1,0,5,2,8 };size_t sz = sizeof(arr) / sizeof(arr[0]);sort(arr, sz);  // 插入排序优化for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

4. 快速排序 

4.1 原理

核心思想是分治法一分为二,左边比某个基准数小,右边比某个基准数大,左边右边又一分为二,直至不可再分

 

4.2 具体步骤

  1. 从数列中随便挑一个数作为基准数(我选的是最后一个数);

  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。

  3. 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序;

4.3 代码实现 

关键点:递归的思想,函数要被调用,要写得一般一些

#include<stdio.h>
/*
函数功能:将最后一个元素作为基准数小于它的放左边,大于它的放右边
返回值:基准数最后的位置
*/
int partition(int arr[], int start, int end)
{// 遍历基准元素前的所有元素for (int i = end - 1; i >= start; i--){if (arr[i] > arr[end]){int temp = arr[i];arr[i] = arr[end - 1];arr[end - 1] = arr[end];arr[end] = temp;end -= 1;}}return end;//  2 1 3 2
}void QuickSort(int arr[], int start, int end)
{if (start < end){// 函数最后返回的是排过后基准元素的位置int pivot = partition(arr, start, end);// 递推式的一分为二QuickSort(arr, start, pivot - 1);QuickSort(arr, pivot + 1, end);}
}int main()
{int arr[] = { 9,6,8,-1,0,5,2,8 };size_t sz = sizeof(arr) / sizeof(arr[0]);// 以后还要调用,需写得一般一些QuickSort(arr, 0, sz - 1);  // 快速排序for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

4.4 优化 

快速排序的效率在于其平均时间复杂度为O(nlogn),这使其成为实际应用中非常受欢迎的一种排序算法。然而,在最坏的情况下,其时间复杂度会退化到O(n^2),这通常发生在每次选择的基准都是最大或最小元素时。为了避免这种情况,可以采用随机选择基准或者三数取中等策略来优化快速排序的性能。下面演示随机选择的优化

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
/*
函数功能:将最后一个元素作为基准数小于它的放左边,大于它的放右边
返回值:基准数最后的位置
*/
int partition(int arr[], int start, int end)
{int end_temp = end;end = rand() % (end - start) + start + 1;// 把左边大的甩到右边for (int i = end - 1; i >= start; i--){if (arr[i] > arr[end]){int temp = arr[i];arr[i] = arr[end - 1];arr[end - 1] = arr[end];arr[end] = temp;end -= 1;}}// 把右边小的甩到左边for (int i = end + 1; i <= end_temp; i++){if (arr[i] < arr[end]){int temp = arr[i];arr[i] = arr[end + 1];arr[end + 1] = arr[end];arr[end] = temp;end += 1;}}return end;//  2 1 3 2
}void QuickSort(int arr[], int start, int end)
{if (start < end){// 函数最后返回的是排过后基准元素的位置int pivot = partition(arr, start, end);// 递推式的一分为二QuickSort(arr, start, pivot - 1);QuickSort(arr, pivot + 1, end);}
}int main()
{srand((unsigned int)time(NULL));int arr[] = { 9,6,8,-1,0,5,2,8 };size_t sz = sizeof(arr) / sizeof(arr[0]);// 以后还要调用,需写得一般一些QuickSort(arr, 0, sz - 1);  // 快速排序for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

感谢观看!!!

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

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

相关文章

linux动态库加载相关

linux下动态库搜索规则 (1)编译目标代码时指定的动态库搜索路径,也就是RPATH&#xff1b; (2)环境变量LD_LIBRARY_PATH指定的动态库搜索路径&#xff1b; (3)配置文件/etc/ld.so.conf中指定的动态库搜索路径&#xff1b;配置完毕后需运行ldconfig命令生效&#xff1b; (4)默…

Linux课程四课---Linux开发环境的使用(vim编辑器的相关)

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

【MySQL】内置函数 -- 详解

一、日期函数 日期&#xff1a;年月日时间&#xff1a;时分秒 1、获得年月日 2、获得时分秒 3、获得时间戳 4、在日期的基础上加日期 5、在日期的基础上减去时间 6、计算两个日期之间相差多少天 7、获得当前时间 ⚪练习 &#xff08;1&#xff09;记录生日 &#xff08;2&…

视频监控简史

安防系统中,视频监控始终是重头戏,是安防系统的核心。 目录 一、起步 二、模拟时代 三、数字时代 四、嵌入式存储 五、视频编码器 六、全数字化监控

Flask入门一(介绍、Flask安装、Flask运行方式及使用、虚拟环境、调试模式、配置文件、路由系统)

文章目录 一、Flask介绍二、Flask创建和运行1.安装2.快速使用3.Flask小知识4.flask的运行方式 三、Werkzeug介绍四、Jinja2介绍五、Click CLI 介绍六、Flask安装介绍watchdog使用python--dotenv使用&#xff08;操作环境变量&#xff09; 七、虚拟环境介绍Mac/linux创建虚拟环境…

家政按摩上门服务小程序搭建

家政按摩上门服务小程序支持技师入驻申请&#xff0c;用户可以通过在线下单预约家政服务&#xff0c;并根据距离、价格、销量好评度等条件进行筛选和选择。用户可以选择技师进行预约&#xff0c;并填写自己的服务地点和时间&#xff0c;享受上门服务。同时&#xff0c;技师也可…

【MySQL】_自连接与子查询、

目录 1. 自连接 2. 子查询&#xff08;嵌套查询&#xff09; 2.1 子查询分类 2.2 单行子查询示例1&#xff1a;查询不想毕业同学的同班同学 2.3 多行子查询示例2&#xff1a;查询语文或英语课程的信息成绩 3. 合并查询 3.1 示例1&#xff1a;查询id3或者名字为英文的课程…

数据分析-Pandas数据探查初步柱状图

数据分析-Pandas数据探查初步柱状图 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表&am…

在Arcgis中删除过滤Openstreetmap道路属性表中指定highway类型道路

一、导出道路类型并分析 1. 导出道路类型 选中highway属性列&#xff0c;选择汇总→确定 2. 分析 用Excel打开输出表&#xff0c;包含的道路类型如下 0.空值’’ 车辆可行驶道路&#xff08;和bfmap的并集&#xff09; 空值&#xff08;无定义道路&#xff09; 二、…

Docker - compose常用命令(常规操作顺序)

----------------------------------------------------------【Docker】-------------------------------------------------------------------- 【本地部署】 构建Docker镜像 docker build -t your-image-name .运行容器 docker run -p 8080:8700 your-image-name , 本地验…

基于Vue(提供Vue2/Vue3版本)和.Net Core前后端分离、强大、跨平台的快速开发框架

前言 今天大姚给大家推荐一款基于Vue&#xff08;提供Vue2/Vue3版本&#xff09;和.Net Core前后端分离、开源免费&#xff08;MIT License&#xff09;、强大、跨平台的快速开发框架&#xff0c;并且框架内置代码生成器&#xff08;解决重复性工作&#xff0c;提高开发效率&a…

element el-table表格内容宽度自适应,不换行,不隐藏

2024.2.27今天我学习了如何用el-table实现表格宽度的自适应&#xff0c;当我们动态渲染表格数据的时候&#xff0c;有时候因为内容太多会出现挤压换行的效果&#xff1a; 我们需要根据内容的最大长度设置动态的宽度&#xff0c;这边我在utils里面封装了一个js&#xff1a; //…

求两个向量之间的夹角

求两个向量之间的夹角 介绍Unity的API求向量夹角Vector3.AngleVector3.SignedAngle 自定义获取方法0-360度的夹角 总结 介绍 求两个向量之间的夹角方法有很多&#xff0c;比如说Unity中的Vector3.Angle&#xff0c;Vector3.SignedAngle等方法&#xff0c;具体在什么情况下使用…

高性能Server的基石:reactor反应堆模式

业务开发同学只关心业务处理流程。但是我们开发的程序都是运行服务端server上&#xff0c;服务端server接收到IO请求后&#xff0c;是如何处理请求并最终进入业务流程的呢&#xff1f;这里不得不提到reactor反应堆模型。reactor反应堆模型来源于大师Doug Lea在 《Sacalable io …

Unity中URP下实现水体(水面反射)

文章目录 前言一、原理1、法一&#xff1a;使用立方体纹理 CubeMap&#xff0c;作为反射纹理使用2、法二&#xff1a;使用反射探针生成环境反射图&#xff0c;所谓反射的采样纹理 二、实现水面反射1、定义和申明CubeMap2、反射向量需要什么3、计算 N ⃗ \vec{N} N 4、计算 V ⃗…

Mybatis | Mybatis的“入门程序“

Mybatis的入门程序 目录: Mybatis的入门程序一、查询数据根据表 “主键id” 查询数据模糊查询 二、添加数据三、更新数据四、删除数据 作者简介 &#xff1a;一只大皮卡丘&#xff0c;计算机专业学生&#xff0c;正在努力学习、努力敲代码中! 让我们一起继续努力学习&#xff0…

Freesia项目介绍

项目介绍 这是一个Spring Boot Vue的前后端分离项目&#xff0c;实现的是一个通用的后台管理系统。 框架使用 前端使用了layui-vue和layui-vue-admin&#xff0c;分别提供了组件和前端整体架构的支持。 后端使用Spring Boot框架管理 项目技术使用 前端 Layui-vue、Layui…

Android 接入指纹识别

接入指纹框架&#xff1a;https://github.com/Tencent/soter implementation com.github.Tencent.soter:soter-wrapper:2.0.91.Application中初始化 class IApplication : Application() {override fun onCreate() {super.onCreate()instance thisinitSort()}private fun in…

Java8 Stream操作流10条常用方法

1.基础数据 Data AllArgsConstructor NoArgsConstructor public class User {private String name;private Integer age;private String sex;private String city; //城市private Integer money; //业绩金额 } //准备数据List<User> users new ArrayList<>();use…

UnityWebGL UGUI中文不显示问题

这是Unity编辑中效果 打包成webgl后的效果&#xff08;中文没有显示出来&#xff09; 解决方法 将Unity默认使用的Arial替换成中文字体。 1.找到电脑字体库&#xff08;win电脑字体库路径&#xff1a;C:\Windows\Fonts &#xff1b;Mac电脑搜索“字体册”&#xff09;。 2.将…