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

目录

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.rhkb.cn/news/133463.html

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

相关文章

spring_javaConfig实现配置

现在我们尝试不使用Spring的XML文件来配置了&#xff0c;全权交给Java来做 1 编写pojo类 这个类要被Spring接管&#xff0c;要被注册到容器中 添加Component注解通过Value注解来为属性注入值 package com.wq.pojo;import org.springframework.beans.factory.annotation.Value…

利用芯片74hc165为单片机增加输入扩展端口proteus仿真arduino

我们前面的博文《输入端口少如何扩展&#xff1f;74hc148或74ls148级联在arduino中实现16转4的应用》介绍了148,148输入后可以立即输出到数码管&#xff0c;可以说它是自带编BCD编码器的。而今天这里我们主要介绍的74hc165是没有编码器&#xff0c;这里我们以proteus为仿真环境…

CMake高级用法实例分析(学习paddle官方的CMakeLists)

cmake基础学习教程 https://juejin.cn/post/6844903557183832078 官方完整CMakeLists cmake_minimum_required(VERSION 3.0) project(PaddleObjectDetector CXX C)option(WITH_MKL "Compile demo with MKL/OpenBlas support,defaultuseMKL." ON) o…

GaussDB(DWS)云原生数仓技术解析:湖仓一体,体验与大数据互联互通

文章目录 前言一、关于数据仓库需求场景分类二、数据仓库线下部署场景2.1、线下部署场景介绍及优劣势说明2.2、线下部署场景对应的客户需求 三、数据仓库公有云部署场景3.1、公有云部署场景介绍及优劣势说明3.2、公有云部署场景对应的客户需求 四、为何重视数据共享&#xff08…

postgresql-视图

postgresql-视图 视图概述使用视图的好处 创建视图修改视图删除视图递归视图可更新视图WITH CHECK OPTION 视图概述 视图&#xff08;View&#xff09;本质上是一个存储在数据库中的查询语句。视图本身不包含数据&#xff0c;也被称为 虚拟表。我们在创建视图时给它指定了一个…

IAM、EIAM、CIAM、RAM、IDaaS 都是什么?

后端程序员在做 ToB 产品或者后台系统时&#xff0c;都不可避免的会遇到账号系统、登录系统、权限系统、日志系统等这些核心功能。这些功能一般都是以 SSO 系统、RBAC 权限管理系统等方式命名&#xff0c;但这些系统合起来有一个专有名词&#xff1a;IAM。 IAM IAM 是 Identi…

数学建模__线性规划Python实现

我使用到的是python库中scipy。 线性规划 #目标函数的系数 # min z 2x13x2-5x3 c np.array([-2,-3,5])#不等式限制条件的系数&#xff0c;转化为小于等于 # 2x1-5x2x3 < 10, x13x2x3<12 Aup np.array([[-2,5,-1],[-1,-3,-1]]) #必须是二维 #右侧系数 bup np.array(…

论文管理系统设计与实现

毕业论文管理系统的设计与实现 学生&#xff1a; 指导教师&#xff1a; 内容摘要&#xff1a;毕业论文管理系统是典型的MIS信息管理系统,其开发主要包括后台数据库的建立和维护以及前端应用程序的开发两个方面。对于前者要求建立起数据一致性和完整性强、数据安全性好的库。而…

如何将一个字符串转换为驼峰命名法(camel case)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 思路⭐ 示例⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领…

【毕设选题】flink大数据淘宝用户行为数据实时分析与可视化

文章目录 0 前言1、环境准备1.1 flink 下载相关 jar 包1.2 生成 kafka 数据1.3 开发前的三个小 tip 2、flink-sql 客户端编写运行 sql2.1 创建 kafka 数据源表2.2 指标统计&#xff1a;每小时成交量2.2.1 创建 es 结果表&#xff0c; 存放每小时的成交量2.2.2 执行 sql &#x…

康耐视读码器DataMan软件详细使用步骤

1、 点击桌面已经安装好的 dataman 软件并打开 2、 打开之后,点击刷新,刷出来读码器的图标,双击进行连接,或者选中后,点击右下角 的连接。(也可先进行第 9—(2)步更改读码器的 IP,对应的连接对象也更改到同一网 段)如图 3、 连接之后,在设置 快速设置下面把实时显…

【栈与队列面试题】有效的括号(动图演示)

leetcode20.括号匹配问题 前言&#xff1a; &#x1f4a5;&#x1f388;个人主页:​​​​​​Dream_Chaser&#xff5e; &#x1f388;&#x1f4a5; ✨✨刷题专栏:http://t.csdn.cn/UlvTc ⛳⛳本篇内容:力扣上栈与队列的面试OJ题目 目录 leetcode20.括号匹配问题 1.问题描…

msvcp120.dll怎么修复?msvcp120.dll丢失的解决方法

在当今这个信息化的时代&#xff0c;电脑已经成为我们生活和工作中不可或缺的一部分。然而&#xff0c;随着电脑技术的不断发展&#xff0c;我们也会遇到各种各样的问题。其中&#xff0c;msvcp120.dll丢失是一个常见的问题。一、msvcp120.dll 文件介绍 1 msvcp120.dll 文件的定…

关于 firefox 不能访问 http 的解决

情景&#xff1a; 我在虚拟机 192.168.x.111 上配置了 DNS 服务器&#xff0c;在 kali 上设置 192.168.x.111 为 DNS 服务器后&#xff0c;使用 firefox 地址栏搜索域名 www.xxx.com &#xff0c;访问在 192.168.x.111 搭建的网站&#xff0c;本来经 192.168.x.111 DNS 服务器解…

MATLAB入门-数据的导入和导出

MATLAB入门-数据的导入和导出 注&#xff1a;本篇文章是课程学习笔记&#xff0c;课程链接为&#xff1a;头歌 常见的几个导入数据的方法 load函数 load函数专门用于引入MATLAB的.mat格式数据&#xff0c;十分的简单方便。 例如&#xff1a;一个-ASCII编码形式存储的数据文件…

VMware启用共享文件夹

1. 启用 编辑虚拟机设置 - 选项 - 共享文件夹 - 总是启用 - 添加 2. 启动Ubuntu查看 正常情况/mnt目录会出现文件夹hgfs 如果不存在&#xff0c;可参考 这篇文章 操作 如果安装VMWare tools后/mnt中有hgfs但没共享文件&#xff0c;可参考 这篇文章 如果出现 mount: unkno…

【Unity每日一记】资源加载相关和检测相关

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

ROS学习笔记(四)---使用 VScode 启动launch文件运行多个节点

ROS学习笔记文章目录 01. ROS学习笔记(一)—Linux安装VScode 02. ROS学习笔记(二)—使用 VScode 开发 ROS 的Python程序&#xff08;简例&#xff09; 03. ROS学习笔记(三)—好用的终端Terminator 一、什么是launch文件 虽然说Terminator终端是能够比较方便直观的看运行的节点…

查看视频文件关键帧间隔

一、Elecard StreamEye Tools拖放视频文件查看。 红的是I帧&#xff1b;蓝的是P帧&#xff1b;绿的是B帧。 二、ffprobe -show_streams统计。 1、统计视频关键帧、非关键帧 ffprobe.exe -i 1.mp4 -show_streams v -show_packets -print_format json > d:\1.json 再统计1.j…

SQL8 查找某个年龄段的用户信息

描述 题目&#xff1a;现在运营想要针对20岁及以上且23岁及以下的用户开展分析&#xff0c;请你取出满足条件的设备ID、性别、年龄。 用户信息表&#xff1a;user_profile iddevice_idgenderageuniversityprovince12138male21北京大学Beijing23214male复旦大学Shanghai36543…