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

目录

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]; //选择最后一个作为基准// 初始化较小元素的索引//递归里面的low 不一定是0开始的所以,写成0 一定报错int index = low;for (int j = low; j <= high - 1; j++){if (arr[j] <= pivot){swap(arr[j], arr[index]);index++;}}// 最后交换arr[i+1]和arr[high],将基准元素放在正确的位置swap(arr[index], arr[high]);return index;
}void quickSort(vector<int> &arr, int low, int high)
{if (low < high) //[0,0 ]就不在判断了。{// 获取基准元素的索引int pivotIndex = partition(arr, low, high);// 对基准元素的左边和右边子数组进行递归排序quickSort(arr, low, pivotIndex - 1);quickSort(arr, pivotIndex + 1, high);}
}

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.hqwc.cn/news/115871.html

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

相关文章

从统计语言模型到预训练语言模型---预训练语言模型(BERT,GPT,BART系列)

基于 Transformer 架构以及 Attention 机制&#xff0c;一系列预训练语言模型被不断提出。 ​BERT 2018 年 10 月&#xff0c; Google AI 研究院的 Jacob Devlin 等人提出了 BERT (Bidirectional Encoder Representation from Transformers ) 。具体的研究论文发布在 arXiv …

Guava Cache介绍-面试用

一、Guava Cache简介 1、简介 Guava Cache是本地缓存&#xff0c;数据读写都在一个进程内&#xff0c;相对于分布式缓存redis&#xff0c;不需要网络传输的过程&#xff0c;访问速度很快&#xff0c;同时也受到 JVM 内存的制约&#xff0c;无法在数据量较多的场景下使用。 基…

如何用好免费的ChatGPT

如何用好免费的ChatGPT 前言ChatGPT使用入口在线体验地址&#xff1a;点我体验 ChatGPT介绍ChatGPT初级使用技巧初级使用技巧&#xff1a;清晰明了的问题表达 ChatGPT中级使用语法中级使用语法&#xff1a;具体化问题并提供背景信息 ChatGPT高级使用高级使用&#xff1a;追问、…

出现 conda虚拟环境默认放在C盘 解决方法

目录 1. 问题所示2. 原理分析3. 解决方法3.1 方法一3.2 方法二1. 问题所示 通过conda配置虚拟环境的时候,由于安装在D盘下,但是配置的环境默认都给我放C盘 通过如下命令:conda env list,最后查看该环境的确在C盘下 2. 原理分析 究其根本原因,这是因为默认路径没有足够的…

MySQL常见面试题(一)

&#x1f600;前言 在数据库管理系统中&#xff0c;存储引擎起着核心的角色&#xff0c;它决定了数据管理和存储的方式。MySQL作为一个领先的开源关系型数据库管理系统&#xff0c;提供了多种存储引擎来满足不同的需求和优化不同的应用。除了选择合适的存储引擎&#xff0c;数据…

差值结构的顺序偏好

( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点&#xff0c;AB训练集各由5张二值化的图片组成&#xff0c;让A 中有5个点&#xff0c;B中有1个点&#xff0c;且不重合&#xff0c;统计迭代次数并排序。 第一种情况 差值结构 迭代次数 L E - - 2 10491.…

想搭建数字藏品平台怎么做?

搭建数字藏品平台涉及多个步骤和技术方面的考虑。以下是创建数字藏品平台的一般步骤&#xff1a; 技术架构 选择合适的技术架构和平台。您可以选择使用现有的电子商务平台、自定义开发、或使用数字藏品管理系统等。云托管服务如Amazon Web Services 或Microsoft Azure也可以提…

科学数据分析和图形绘制软件GraphPad Prism 9 mac中文版特点介绍

Prism 9 mac是一款专业的科学数据分析和图形绘制软件&#xff0c;可用于在生物、医学、化学等领域进行数据分析、绘制图形、进行统计分析等。 Prism 9 mac软件特点 1. 多种数据分析功能&#xff1a;Prism 9提供了多种常见的数据分析工具&#xff0c;包括线性回归、ANOVA、t检验…

gym_unity学习笔记

最近学了一段时间gym_unity&#xff0c;把一些资料留在这里 实例 实例gym_unity训练RollerBall&#xff1a;https://blog.csdn.net/alibutter/article/details/120908687实例gyn_unity训练3DBall&#xff1a;https://zhuanlan.zhihu.com/p/554927641?utm_id0 源码&#xff1…

MySQL数据库详解 二:数据库的高级语言和操作

文章目录 1. 克隆表 ---- 将数据表的数据记录生成到新的表中1.1 方式一&#xff1a;先创建新表&#xff0c;再导入数据1.2方式二&#xff1a;创建的时候同时导入 2. 清空表 ---- 删除表内的所有数据2.1 delete删除2.2 truncate删除&#xff08;重新记录&#xff09;2.3 创建临时…

PowerShell切换多个java版本

安装jdk1.8 和 jdk17 下载jdk 前往 oracle官网下载 配置环境变量 变量名 CLASSPATH变量值 .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar效果图&#xff1a; 变量名&#xff08;jdk1.8同理&#xff09; JAVA_HOME17变量值 C:\Program Files\Java\jdk-17效果图&#xff1…

JavaScript - canvas - 放大镜

效果 示例 项目结构&#xff1a; 源码&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8" /><title>放大镜</title><style type"text/css">div {width: 200px;height: 200px;display: inline-bl…