数据结构与算法--排序算法复习

目录

1.三种常见的简单排序:

1.1冒泡排序

1.2 选择排序

1.3 插⼊排序

2 常见高级排序算法

 2.1 希尔排序

2.2 快速排序

2.3 归并排序

2.4计数排序 


先上结论:

1.三种常见的简单排序:

1.1冒泡排序

1.⾸先在未排序数组的⾸位开始,和后⾯相邻的数字进⾏⽐较,如果前⾯⼀个⽐后⾯⼀个⼤
那么则进⾏交换。
2.接下来在将第⼆个位置的数字和后⾯相邻的数字进⾏⽐较,如果⼤那么则进⾏交换,直到将最⼤的数字交换的数组的尾部。
3.然后再从排序的数组的⾸位开始,重复前⾯两部将最⼤的数字交换到未排序数组的尾部 (交换到尾部的数字是已经拍好序的)。 如此反复,直到排序完毕。
代码。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;void bubbleSort(vector<int> &v)
{for (int i = 0; i < v.size() - 1; i++){for (int j = 0; j < v.size() - i - 1; j++){if (v[j] > v[j + 1]){swap(v[j], v[j + 1]);}}}
}int main()
{vector<int> v = {10, 8, 2, 3, 1, 6, 7, 5, 4, 9};bubbleSort(v);for (auto i : v){cout << i << endl;}system("pause");return 0;
}

1.2 选择排序

 
1⾸先在未排序序列中找到最⼩(⼤)元素,存放到排序序列的起始位置,
2.然后,再从剩余未排序元素中继续寻找最⼩(⼤)元素,然后放到已排序序列的末尾。
3.以此类推,直到所有元素均排序完毕。

void selectionSort(vector<int> &arr)
{int n = arr.size();int min_index; //最小值对应的index;for (int i = 0; i < arr.size(); i++){min_index = i; //默认最小值对应的起始索引是当前位置for (int j = i; j < arr.size(); j++){if (arr[j] < arr[min_index]){min_index = j;}}swap(arr[i], arr[min_index]);}
}

1.3 插⼊排序

1 从第⼀个元素开始,该元素可以认为已经被排序;
2 取出下⼀个元素,在已经排序的元素序列中从后向前扫描;
3 如果该元素(已排序)⼤于新元素,将该元素移到下⼀位置;
4 重复步骤 3 ,直到找到已排序的元素⼩于或者等于新元素的位置;
5 将新元素插⼊到该位置后;
6 重复步骤 2~5
// 插入排序函数
void insertionSort(vector<int> &arr)
{int n = arr.size();for (int i = 1; i < n; ++i){int key = arr[i];int j = i - 1;// 将大于key的元素向后移动while (j >= 0 && arr[j] > key){arr[j + 1] = arr[j];j = j - 1;}// 插入key到正确的位置arr[j + 1] = key;}
}

2 常见高级排序算法

       2.1 希尔排序

2.1 算法描述
1959 Shell 发明,第⼀批突破 O(n2) 时间复杂度的排序算法,是简单插⼊排序的改进版。它与插⼊排序的不同之处在于,它会优先⽐较距离较远的元素。希尔排序⼜叫缩⼩增 量排序
算法核⼼思想是先将整个待排序的记录序列分割成为若⼲⼦序列分别进⾏直接 插⼊排序 ,具体算法描述:
1.先根据数组的⻓度 /n ,获取增量 K (第⼀次 n 2
2.按增量序列个数 k 进⾏分组,⼀般可以分成 k 组;
3.根据以分好的组进⾏插⼊排序;(每组排序,根据对应的增量 k 来找到当前组的元素)
4.当每组都排序完毕之后,回到第⼀步将 n*2 再次分组进⾏插⼊排序,直到最终 k=1 的时候,在执⾏⼀次插⼊排序 完成最终的排序

void shellSort(vector<int> &arr)
{int n = arr.size();// 使用一组增量进行排序for (int gap = n / 2; gap > 0; gap /= 2){// 对每个增量进行插入排序for (int i = gap; i < n; i++){int temp = arr[i];int j;// 将元素插入到正确的位置for (j = i; j >= gap && arr[j - gap] > temp; j -= gap){arr[j] = arr[j - gap];}arr[j] = temp;}}
}

2.2 快速排序

快速排序是对冒泡排序的⼀种改进,通过分⽽治之的思想减少排序中交换和遍历的次数,整个过程可以通过递归的⽅式完成。
具体描述如下 :
1 ,⾸先通过⽐较算法 , 找到基准数,⽐较过程通过交换,最终达到基准数左边的数字都⽐较右边的要⼩。分⽐在头尾设置两个指针,并且再将尾部元素作为⽐较基准。
移动 L R 两个指针,直到重合,然后交换基准数字
2 ,然后以基准数作为中轴,将数组分为两部分,分⽐执⾏ 1 步骤的算法(可以通过递
归实现),直到⽆法再次分割排序完毕。
   递归
⼀个含直接或间接调⽤本函数语句的函数被称之为递归函数,它必须满⾜以下两个条件:
1 ) 在每⼀次调⽤⾃⼰时,必须是(在某种意义上)更接近于解;
2 ) 必须有⼀个终⽌处理或计算的准则。
 算法实现
分解 1 :创建左右两个指针,将最后⼀个值作为基准值,通过不断交换将数组分为两部
分,左边的⽐右边的要⼩。
先判断左指针和基准的值,如果⼩于等于就向后移动,直到遇到⽐基准值⼤的值
再判断右边指针和基准值,如果⼤于等于就向前移动,直到遇到⽐基准值⼩的值
然后交换左右指针的值。
循环上述操作,直到左右指针重合,然后交换重合值和基准值

// 根据基准元素将数组分成两部分,并返回基准元素的索引
int partition(vector<int> &arr, int low, int high)
{int pivot = arr[high]; // 选择最后一个元素作为基准int i = (low - 1);     // 初始化较小元素的索引for (int j = low; j <= high - 1; j++){// 如果当前元素小于或等于基准元素,则交换arr[i+1]和arr[j]if (arr[j] <= pivot){i++;swap(arr[i], arr[j]);}}// 最后交换arr[i+1]和arr[high],将基准元素放在正确的位置swap(arr[i + 1], arr[high]);return (i + 1);
}// 快速排序主函数
void quickSort(vector<int> &arr, int low, int high)
{if (low < high){// 获取基准元素的索引int pivotIndex = partition(arr, low, high);// 对基准元素的左边和右边子数组进行递归排序quickSort(arr, low, pivotIndex - 1);quickSort(arr, pivotIndex + 1, high);}
}int main()
{vector<int> v = {10, 8, 2, 3, 1, 6, 7, 5, 4, 9};// bubbleSort(v);// selectionSort(v);// insertionSort(v);// shellSort(v);quickSort(v, 0, v.size() - 1);for (auto i : v){cout << i << endl;}system("pause");return 0;
}

2.3 归并排序

1.归并排序是利⽤ 归并 的思想实现的排序⽅法,该算法采⽤经典的 分治 策略即将问题 成⼀
些⼩的问题然后 递归 求解,⽽ 的阶段则将分的阶段得到的各答案 " 修补 " 在⼀起,即分⽽
治之
2.
归并排序是稳定排序,它也是⼀种⼗分⾼效的排序,能利⽤完全⼆叉树特性的排序⼀般性
能都不会太差。 java Arrays.sort() 采⽤了⼀种名为 TimSort 的排序算法,就是归并排序
的优化版本。从上⽂的图中可看出,每次合并操作的平均时间复杂度为 O(n) ,⽽完全⼆叉
树的深度为 |log2n| 。总的平均时间复杂度为 O(nlogn) 。⽽且,归并排序的最好,最坏,
平均时间复杂度均为 O(nlogn)
归并排序核⼼思想是先分再治 , 具体算法描述如下 :
1.先将未排序数组 /2 进⾏分组 , 然后再将分好组的数组继续 /2 再次分组 , 直到⽆法分组 ,
个就是分的过程 .
2.然后在将之后再把两个数组⼤⼩为 1 的合并成⼀个⼤⼩为 2 的,再把两个⼤⼩为 2 的合
并成 4 , 同时在合并的过程中完成数组的排序 , 最终直到全部⼩的数组合并起来 , 这个
就是治的过程 .

       

治的过程中会为两个数组设计两个游标 , 和⼀个新的数组 .
        分⽐⽐较两个游标指对应数组的元素, 将⼩的插⼊到新的数组中
        然后向后移动较⼩的数组的游标, 继续进⾏⽐较 .
        反复前⾯两步, 最终将两个数组中的元素排序合并到新的数组中

#include <iostream>
#include <vector>// 合并两个已排序的子数组
void merge(std::vector<int>& arr, int left, int mid, int right) {int n1 = mid - left + 1;int n2 = right - mid;// 创建临时数组来存储两个子数组std::vector<int> leftArr(n1);std::vector<int> rightArr(n2);// 将数据复制到临时数组中for (int i = 0; i < n1; i++) {leftArr[i] = arr[left + i];}for (int i = 0; i < n2; i++) {rightArr[i] = arr[mid + 1 + i];}// 合并两个子数组int i = 0, j = 0, k = left;while (i < n1 && j < n2) {if (leftArr[i] <= rightArr[j]) {arr[k] = leftArr[i];i++;} else {arr[k] = rightArr[j];j++;}k++;}// 处理剩余的元素(如果有)while (i < n1) {arr[k] = leftArr[i];i++;k++;}while (j < n2) {arr[k] = rightArr[j];j++;k++;}
}// 归并排序函数
void mergeSort(std::vector<int>& arr, int left, int right) {if (left < right) {// 找到数组中间点int mid = left + (right - left) / 2;// 递归排序左半部分和右半部分mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);// 合并已排序的两个子数组merge(arr, left, mid, right);}
}int main() {std::vector<int> arr = {12, 11, 13, 5, 6, 7};std::cout << "原始数组: ";for (int num : arr) {std::cout << num << " ";}std::cout << std::endl;// 调用归并排序函数mergeSort(arr, 0, arr.size() - 1);std::cout << "排序后数组: ";for (int num : arr) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

 

2.4计数排序 

计数排序是⼀个⾮基于⽐较的排序算法,该算法于 1954 年由 Harold H. Seward 提出。它的优势在于在对⼀定范围内的整数排序时,它的复杂度为Ο (n+k) (其中 k 是整数的范围),快于任何⽐较排序算法。 当然这是⼀种牺牲空间换取时间的做法,⽽且当 O(k)>O(nlog(n))的时候其效率反⽽不如基于⽐较的排序(基于⽐较的排序的时间复杂度在理论上的下限是O(nlog(n)), 如归并排序,堆排序)计数排序是⼀种适合于最⼤值和最⼩值的差值不是不是很⼤的排序,也就是说重复的数据
会⽐较多的情况。具体实现过程如下:⾸先遍历整个数组,找到最⼤的数字。
          然后根据最⼤的数字创建⼀个临时统计数组,⽤于统计每个数字出现的次数,例如temp[i] = m, 表示元素 i ⼀共出现了 m 次。最后再把临时数组统计的数据从⼩到⼤返回到原来的数组中,这样就是有序的。

实现:

        

#include <iostream>
#include <vector>void countingSort(std::vector<int>& arr) {int max_val = *std::max_element(arr.begin(), arr.end()); // 找到数组中的最大值int min_val = *std::min_element(arr.begin(), arr.end()); // 找到数组中的最小值int range = max_val - min_val + 1; // 计算数值范围// 创建计数数组并初始化为0std::vector<int> count(range, 0);// 计算每个元素的出现次数for (int num : arr) {count[num - min_val]++;}// 根据计数数组,重建原始数组int index = 0;for (int i = 0; i < range; i++) {while (count[i] > 0) {arr[index] = i + min_val;index++;count[i]--;}}
}int main() {std::vector<int> arr = {4, 2, 2, 8, 3, 3, 1};std::cout << "原始数组: ";for (int num : arr) {std::cout << num << " ";}std::cout << std::endl;// 调用计数排序函数countingSort(arr);std::cout << "排序后数组: ";for (int num : arr) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

 

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

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

相关文章

Vue 3的革命性新特性:深入了解Composition API

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

安装深度(Deepin)系统

Deepin系统安装 Deepin是和Ubuntu一样&#xff0c;是一个基于Debian的Linux的发型版本。 Deepin相对于Ubuntu&#xff0c;Deepin更适合中国用户的使用习惯。 一 官网工具制作启动盘 制作启动盘、和安装系统&#xff0c;操作非常简单&#xff0c;nice&#xff01; 官网提供了…

C语言 -- 零基础入门详解

文章目录 引言1. 第一个C语言程序&#xff1a;HelloWorld1.1 编写C语言代码&#xff1a;hello.c1.2 代码分析 2. 数据类型2.1 常量与变量2.1.1 关键字2.1.2 数据类型2.1.3 常量2.1.4 变量2.1.5 使用示例 2.2 整型&#xff1a;int2.2.1 整型变量的定义和输出2.2.2 整型变量的输入…

VRTK4⭐二.VRTK4的项目基础配置

文章目录 &#x1f7e5; 硬件基本配置&#x1f7e7; 设置XR Plug-in Management&#x1f7e8; 添加项目Tilia&#x1f7e9; 配置项目Hierarchy &#x1f7e5; 硬件基本配置 解决使用OpenXR,HTC头显正常追踪,但手柄无法使用的问题. 问题如下: 当我们按照官方的标准流程配置完Op…

Apache Kafka 基于 S3 的数据导出、导入、备份、还原、迁移方案

在系统升级或迁移时&#xff0c;用户常常需要将一个 Kafka 集群中的数据导出&#xff08;备份&#xff09;&#xff0c;然后在新集群或另一个集群中再将数据导入&#xff08;还原&#xff09;。通常&#xff0c;Kafka集群间的数据复制和同步多采用 Kafka MirrorMaker&#xff0…

负载均衡-ribbon源码解析

负载均衡-ribbon源码解析 1 LoadBalanced注解 /*** 基于ribbon调用服务及负载均衡* return*/ LoadBalanced Bean public RestTemplate restTemplate(){return new RestTemplate(); }Bean ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer(fin…

学习笔记|矩阵按键控制原理|数值转化为键码|密码锁|STC32G单片机视频开发教程(冲哥)|第十四集:矩阵按键原理及实践

文章目录 1.矩阵按键是什么2.矩阵按键的控制原理3.矩阵按键程序的编写将数值转化为键码完整代码&#xff1a;demo.c&#xff1a;key.c:key.h: 密码锁&#xff08;简易版&#xff09;需求分析&#xff1a; 总结课后练习&#xff1a; 1.矩阵按键是什么 这个矩阵按键也是我们这个…

Shell 正则表达式及综合案例及文本处理工具

目录 一、常规匹配 二、常用特殊字符 三、匹配手机号 四、案例之归档文件 五、案例之定时归档文件 六、Shell文本处理工具 1. cut工具 2. awk工具 一、常规匹配 一串不包含特殊字符的正则表达式匹配它自己 例子&#xff0c;比如说想要查看密码包含root字符串的&#x…

Vue3路由

文章目录 Vue3路由1. 载入vue-router 库2. 实例2.1 Vue.js vue-router 实现单页应用2.2 router-link创建链接2.3 router-view显示与url对应组件2.4 <router-link> 相关属性 Vue3路由 1. 载入vue-router 库 Vue.js 路由需要载入vue-router 库 安装直接下载地址&#xf…

Redis模块一:缓存简介

目录 缓存的定义 应用 生活案例 程序中的缓存 缓存优点 缓存的定义 缓存是⼀个高速数据交换的存储器&#xff0c;使用它可以快速的访问和操作数据。 应用 1.CPU缓存&#xff1a;CPU缓存是位于CPU和内存之间的临时存储器&#xff0c;它的容量通常远小于内存&#xff0…

linux安装常见的中间件和数据库

文章目录 一、数据库二、redis三、tomcat四、nginx五、mq六、es七、nacos八、neo4j&#xff08;图数据库&#xff09;九、fastdfs其他 一、数据库 linux环境上使用压缩包安装mysql【数据库】Mysql 创建用户与授权 二、redis redis是没有账号的&#xff0c;只能设置密码Linux…

学信息系统项目管理师第4版系列07_项目管理知识体系

1. 项目管理原则 1.1. 勤勉、尊重和关心他人 1.1.1. 关键点 1.1.1.1. 关注组织内部和外部的职责 1.1.1.2. 坚持诚信、关心、可信、合规原则 1.1.1.3. 秉持整体观 1.1.2. 职责 1.1.2.1. 诚信 1.1.2.2. 关心 1.1.2.3. 可信 1.1.2.4. 合规 1.2. 营造协作的项目管理团队…

Pytorch从零开始实战02

Pytorch从零开始实战——彩色图像识别 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——彩色图像识别环境准备数据集模型选择模型训练数据可视化 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1cu118…

IDM(Internet Download Manager)下载器2024最新版本如何下载?

IDM&#xff08;Internet Download Manager&#xff09;下载器能够兼容支持多种浏览器进行文件下载&#xff0c;很多时候只要复制一个地址IDM的下载弹窗就自动弹出来&#xff0c;有时候不需要下载的时候也会弹&#xff0c;时间久了就会感觉很烦&#xff0c;不过这个问题其实可以…

Python stomp 发送消息无法显示文本

我们向消息服务器通过 stomp 发送的是文本消息。 当消息服务器发送成功后&#xff0c;消息服务器上的文本没有显示&#xff0c;显示的是 2 进制的数据。 如上图&#xff0c;消息没有作为文本来显示。 问题和解决 消息服务器是如何判断发送的小时是文本还是二进制的。 根据官…

go-GC垃圾回收

GC GC是自动化内存管理回收机制 虚拟内存函数栈的数据是会根据函数返回而自动销毁的&#xff0c;而堆上的数据是不会随着函数自动销毁的&#xff0c;堆内数据会随着程序运行而逐渐变大&#xff0c;从而导致内存OOM&#xff0c;Go语言就用了GC来清理堆上的内存数据。 如何区分…

tomcat架构概览

https://blog.csdn.net/ldw201510803006/article/details/119880100 前言 Tomcat 要实现 2 个核心功能&#xff1a; 处理 Socket 连接&#xff0c;负责网络字节流与 Request 和 Response 对象的转化。加载和管理 Servlet&#xff0c;以及具体处理 Request 请求。 因此 Tomc…

CSS盒子模型

盒子模型的组成 CSS会把所有的HTML元素都看成一个盒子&#xff0c;所有的样式也都是基于这个盒子 content&#xff08;内容&#xff09;&#xff1a;盒子的内容padding&#xff08;内边距&#xff09;&#xff1a;用于控制元素内部与边框之间的距离border&#xff08;边框&…

让NPU跑起来迅为RK3588开发板设置交叉编译器

让NPU跑起来迅为RK3588开发板设置交叉编译器 编译器下载地址是网盘资料“iTOP-3588 开发板\02_【iTOP-RK3588 开发板】开发资料 \12_NPU 使用配套资料\03_编译所需工具\Linux”。 拷贝 gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.gz 到 Ubuntu 的/opt/tool_ch…

分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测

分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测 目录 分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测预测效果基本介绍程序设计参考资料致谢 预测效果 基本介绍 Matlab实现基于PCA-GRU主成分分析-门控循环单元多输入分类预测&#xff08;完整程序和数据…