基础排序算法

插入排序(insertion sort)

插入排序每次循环将一个元素放置在适当的位置。像抓牌一样。手里的排是有序的,新拿一张牌,与手里的牌进行比较将其放在合适的位置。

插入排序要将待排序的数据分成两部分,一部分有序,另一部分待排序。默认任务数组第一个元素是有序的,然后依次取剩下的元素插入有序部分合适的位置。

算法实现

   public static void sort(int[] arr){int len = arr.length;/*** 将数组分成两部分* [0] 已排序  & [1,2,3...length-1] 待排序* 第一层循环将待排序元素逐个拿出与已排序部分进行插入排序*/for (int i = 1; i < len; i++) {//先把当前循环要排序的元素从数组拿出来,空出来一个数组位置int val = arr[i];// j 当前插入位置指针int j = i-1;for (; j > 0 ; j--) {if(val < arr[j]){//当前插入指针位置元素比当前待排序值大,将当前位置元素后移arr[j+1] = arr[j];}else {//当前插入指针位置元素比当前值小,好了,就应该在这里插入,插入到指针位置的后面 j+1break;}}arr[j+1] = val;  }}

实际数据分析:

例 {2,6,5,4,8,7}

排序过程: 默认数组第一个位置2已排好,从6开始插入排序。

第一次:把6拿出来,然后6的位置可以被覆盖。

内循环:插入指针为6的下标往前一个,第一次拿出2进行比较。6 >2 。6要插入2的后面,跳出循环

第二次:拿出5 内循环:插入指针为5的下标-1, 第一次拿出6,5<6。不能在这里插入,插入点还得往前移动。这个时候要把6的位置后移一位, 因为5要插入6前面,但是现在没有位置。正好5被拿出来了,5的位置现在可以被使用。 经过一次内循环插入指针移动到了2位置,6向后移动一位。这时数组变成{2,6,6,4,8,7}。内循环第二次拿出2,5>2, ok找到插入点了,跳出内循环,5插入2的后面也就是原来6的位置。 将5放入插入位置,这时候数组变成了{2,5,6,4,8,7}。结束5的排序

第三次依次操作。

插入排序的插入理解就是将待排序的当前元素插入到有序部分合适的位置。比较前先将当前元素拿出来,在比较的过程中,如果当前元素的排序位置没找到,不需要进行交换。只需要将当前有序部分的比较元素后移一位,让出插入位置。进行下一次比较依次类推。直到找到插入位置,将当前元素放入该位置。

插入排序最好情况时间复杂度是O(n)。已经是有序的了,只一遍外循环即可。最坏情况是O(n^2)。排序算法是稳定的,因为不存在交换。也不需要开辟额外的空间。

希尔排序

希尔排序是插入排序的变种。我们知道插入排序的时间复杂度是O(n^2)。一次只能对一个元素位进行排序,并且遇到较小值在数组后部时,要进行多次比较移位才能将其放置合适位置。希尔排序能提高一定的平均排序效率。但是实际中使用的可能也不太多。

排序原理

每次按特定步长(step)将待排序分成若干组,然后每组内进行插入排序。步长取值通常为元素长度 length/2,length/(2*2)…1。最后一次步长变成1演变成完全插入排序。

代码实现

    static void sort(int[] arr){int len = arr.length;//step为步长,分组元素间的间隔for (int step = len/2; step >0; step /=2) {//每一组进行插入排序,for (int i = step; i < len; i++) {//外层循环每+1表示新一组元素int temp = arr[i];//待插入元素先拿出来int p = i;//当前插入指针,p-step是当前组已排序好的部分,依次拿出与当前值进行比较for (; p >= step ; p -= step) {//每次取同组元素,同组元素的间隔是step值if(arr[p - step] > temp){arr[p] = arr[p - step];}else{//找到插入位置break;}}arr[p] = temp;//将元素插入当前位置}}}

实例分析:

image

冒泡排序(Bubble sort)

排序算法像冒泡一样每次遍历通过比较找到待排序元素中最大的一个,然后上浮到已排序部分。

代码实现

    static void sort(int[] arr){int len = arr.length;for (int i = 0; i < len-1; i++) {//len-i个元素已排好,所以内循环次数是len-i-1for (int j = 0; j < len-i-1; j++) {/**前面元素比后面元素大就进行交换,大元素后移。这样内循环结束后就找到了本次所有参与循环元素的最大值,并放到最后。*/if(arr[j] > arr[j+1]){int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}System.out.println(Arrays.toString(arr));;}}

优化:每次冒泡排序内循环记录是否有交换发生。如果没有交换发生,则整个数组已经是有序的了。仔细理解下这句话。代码实现

  static void sort(int[] arr){int len = arr.length;for (int i = 0; i < len-1; i++) {boolean swap = false;for (int j = 0; j < len-i-1; j++) {if(arr[j] > arr[j+1]){int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;swap = true;}}if(!swap) break;//没有交换发生,跳出循环System.out.println(Arrays.toString(arr));;}}

冒泡排序时间复杂度和插入排序一样最好都是O(n),最后是O(n^2)。

选择排序

排序思想

每次从未排序的部分选择最小(或最大)的元素,放到已排序部分的末尾,直到整个数组排序完成。

代码实现

    public static void sort(int[] arr){int len = arr.length;for (int i = 0; i < len-1; i++) {int p = i;//记录最小位置指针,默认记录为本次循环第一个元素位置for (int j = i+1; j < len ; j++) {//如果当前数比原来标记最小数小,记录当前位置为最小数指针if( arr[j] < arr[p] ) p = j;}//找到本次最小数指针,如果指针不是第一个元素,将第一个元素与最小值元素进行位置交换if(p != i){int temp = arr[i];arr[i] = arr[p];arr[p] = temp;}}}

选择排序存在元素跨距离交换,不稳定,时间复杂度O(n^2)。理解起来和冒泡排序很像。不过中间少了很多交换。

归并排序

归并排序将待排序数组每次进行二分,直到每一组分成1个元素,则顺序也就出来了。然后再依次进行合并操作最后生成一个有序的操作。

分比较好操作每次数组进行二分即可。合就是要将分的两部分A、B依次拿出一个值(两部分当前最小的值,中间需要比较是取A部分的还是取B部分)来组合起来。因为分后的两部分已经是有序的了,所以最后两部分所有元素取完合起来的整个也是有序的。

排序过程图:

image

代码实现:

    public static void sort(int[] arr,int start,int end){//元素开始和结束位置相等,不能再分了,结束if(start >= end) return;//将要排序的数组进行平分int mid = (start + end) /2;sort(arr,start,mid);//前半部分进行排序sort(arr,mid+1,end);//后半部分进行排序//合并本次排序结果merge(arr,start,mid,end);}/*** 排序两部分 {start,mid} ,{mid+1,end} 都已排序完成,合并两部分* 合并过程:*/public static void merge(int[] arr,int start,int mid,int end){int p1 = start;//左半部分当前下标int p2 = mid+1;//右半部分当前下标int index = start;//temp临时数组存储下标,从start开始/*** 合并已排序的两部分* 每次从左边部分和右边部分各拿出一个元素进行比较,小的放入数组中,* 然后从小的所在部分再拿出一个与上一次大的元素进行比较*/while (p1 <= mid && p2 <= end){if(arr[p1] < arr[p2]){temp[index++] = arr[p1++];}else{temp[index++] = arr[p2++];}}/*** while 循环结束表示至少数组两部分有一部分取完,但是不一定两部分都取完。* 最后将左边部分和右边部分可能剩余的部分放入临时数组中。*/while (p1 <= mid){temp[index++] = arr[p1++];}while (p2 <= end){temp[index++] = arr[p2++];}/*** 执行到这里 temp{start,end} 部分都已排好序,* 将temp{start,end}部分放入原数组中。*/for (int i = start; i <= end; i++) {arr[i] = temp[i];}}

快速排序

算法思想:

快速排序取数组第一个元素作为基准数,然后将剩余元素与基准数进行比较,比基准数大的放在基准数左边,小的放在基准数右边,基准数在中间。然后再将基准数两个子结果进行递归按上面取基准数排序。最后整个数组变为有序的。

代码实现

    public static void sort(int arr[],int left ,int right){if(left >= right) return;int p1 = left;int p2 = right;int val = arr[left];//取数组第一个元素作为基准数while ( p1 < p2){/*** 从右往左找比基准数小的数* 找到后将其放到p1指针位置*/while (p2 > p1 && arr[p2] >= val)p2--;arr[p1] = arr[p2];/*** 从左往左找找到比基准数大的数* 找到后将其放到p2指针位置,这个时候p2经过上面的查找已经被放到p1位置,可以覆盖*/while (p1 < p2 && arr[p1] <= val)p1++;arr[p2] = arr[p1];//继续交叉查找}//找到中间位置了(左边的数都小于基准数,右边的数都大于基准数),将基准数放到该位置arr[p2] = val;//递归的将数组以基准数为分界点分成两部分,各自进行快速排序sort(arr,left,p2);sort(arr,p2+1,right);}

排序过程分析

首先取数组的第一个元素作为基准数,然后这样数组第一个位置就可以覆盖,然后从数组的末尾往前找比基准数小的数,如果找到就将其移动到原基准数的位置。这个时候刚被移动的元素位置又空出来了,这个时候在从前往后找比基准数大的,找到后在将其放到该位置。循环往复的进行以上操作。直到从后往前找的指针和从前往后找的指针位置相等,表示整个数组已经找完,将基准数放置在该位置。最后数组被分成了:[{小于基准数}{基准数}{大于基准数}]三部分。然后再对小于基准数部分和大于基准数部分进行递归的上面排序过程。直到被分元素只有一个,排序完成。

从上面的分析过程可以看出,快速排序会进行大量的跨距离移位操作,是不稳定的。平均时间复杂度是O(n*logn)

总结

排序算法时间复杂度空间复杂度适用场景
冒泡排序最好情况:O(n) 最坏情况:O(n^2) 平均情况:O(n^2)O(1)小型数据集或部分有序数据集
插入排序最好情况:O(n) ; 最坏情况:O(n^2) ; 平均情况:O(n^2)O(1)小型数据集或部分有序数据集
选择排序始终为O(n^2)O(1)小型数据集
快速排序最好情况:O(nlogn) ; 最坏情况:O(n^2) ;平均情况:O(nlogn)最好情况:O(logn) , 最坏情况:O(n)大型数据集,尤其是无序数据集
归并排序O(nlogn)O(n)大型数据集,尤其是链表结构

如果对排序稳定性有要求,可以选择插入排序、归并排序。如果数据集较小且无序,可以选择冒泡排序、插入排序或选择排序。对于大型数据集,快速排序、归并排序通常效果更好。

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

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

相关文章

Leetcode 409. 最长回文串

文章目录 题目代码&#xff08;9.24 首刷自解&#xff09; 题目 Leetcode 409. 最长回文串 代码&#xff08;9.24 首刷自解&#xff09; class Solution { public:int longestPalindrome(string s) {unordered_map<char, int> mp;for(char c : s) mp[c];int res 0;int…

什么是Selenium?使用Selenium进行自动化测试!

你知道什么是 Selenium 吗&#xff1f;你知道为什么要使用它吗&#xff1f;答案就在本文中&#xff0c;很高兴能够与你共飧。 自动化测试正席卷全球&#xff0c;Selenium 认证是业界最抢手的技能之一。 什么是 Selenium&#xff1f; Selenium 是一种开源工具&#xff0c;用于…

2023蓝帽杯半决赛misc题目复现

后续会逐渐完善&#xff1a; misc--排排坐吃果果 我真是无大语了&#xff0c;对于我的死脑筋&#xff0c;文件一打开是一片白色&#xff0c;但是点开单元格会看到里面有数字&#xff0c;我想到了修改单元格的格式&#xff0c;就是没想到转换字体的颜色&#xff0c;对此我表示…

阿里云ESS弹性伸缩核心概念与基本使用

文章目录 1.ESS弹性伸缩基本概念1.1.弹性伸缩概念1.2.弹性伸缩应用场景1.3.弹性伸缩的应用模式 2.开通ESS弹性伸缩服务3.为KodCloud云盘集群创建弹性伸缩组3.1.创建伸缩组3.2.设置伸缩组的名称、类型、移除策略、健康检查3.3.设置组内实例数、冷却时间、网络类型、扩缩容策略、…

【数据结构与算法】不就是数据结构

前言 嗨喽小伙伴们你们好呀&#xff0c;好久不见了,我已经好久没更新博文了&#xff01;之前因为实习没有时间去写博文&#xff0c;现在已经回归校园了。我看了本学期的课程中有数据结构这门课程&#xff08;这么课程特别重要&#xff09;&#xff0c;因为之前学过一点&#xf…

华为数通方向HCIP-DataCom H12-831题库(单选题:41-60)

第41题 除了虚连接之外,OSPFV3的Hello报文源IPv6地址是哪种类型的IPv6地址? A、IPv6任播地址 B、唯一本地地址 C、全球单播地址 D、链路本地地址 答案: D 解析: 这里题目是源IPv6,不是目的IPv6,与另一题类似 第42题 下列描述中关于MPLS网络中配置静态LSP正确的是? A、…

简单线性回归(Simple Linear Regression)

简单线性回归(Simple Linear Regression) 简单线性回归(Simple Linear Regression)简介理解数据数据处理读取数据数据预览数据探索数据统计信息数据类型查看数据的直方图通过散点图查看数据的相关关系相关系数建立模型创建训练数据和测试数据建立简单线性回归模型查看回归方…

计算机等级考试—信息安全三级真题六

目录 一、单选题 二、填空题 三、综合题 一、单选题

工厂漏水怎么预防?教你一招,百试百灵

随着工业化的迅速发展&#xff0c;工厂和生产设施在现代社会中扮演着至关重要的角色。然而&#xff0c;这些设施在日常运营中也面临着各种各样的风险和挑战&#xff0c;其中之一是水浸事件。 水浸事件可能是由于天灾、设备故障、管道泄漏或人为失误等原因引发的&#xff0c;但无…

基于STM32和LORA组网的养老院智能控制系统设计(第十八届研电赛)

一、整体功能 数据采集从机1采集烟雾浓度&#xff0c;PM2.5浓度&#xff0c;甲醛浓度&#xff1b;从机2采集温湿度&#xff0c;光照强度&#xff0c;噪声强度&#xff0c;老人体感温度&#xff1b;从机3收集厨房饮用水的TDS值。3个数据采集从机将采集到的数据显示在本地OLED屏…

Sqilte3初步教程

文章目录 安装创建数据库创建和删除表插入行数据 安装 Windows下安装&#xff0c;首先到下载页面&#xff0c;下载Windows安装软件&#xff0c;一般是 sqlite-dll-win32-*.zip sqlite-tools-win32-*.zip下载之后将其内容解压到同一个文件夹下&#xff0c;我把它们都放在了D:\…

使用Python+Flask/Moco框架/Fiddler搭建简单的接口Mock服务

一、Mock测试 1、介绍 mock&#xff1a;就是对于一些难以构造的对象&#xff0c;使用虚拟的技术来实现测试的过程mock测试&#xff1a;在测试过程中&#xff0c;对于某些不容易构造或者不容易获取的对象&#xff0c;可以用一个虚拟的对象来代替的测试方法接口mock测试&#x…

查看吾托帮88.47的docker里的tomcat日志

步骤如下 &#xff08;1&#xff09;ssh &#xff08;2&#xff09;ssh root192.168.88.47 等待输入密码&#xff1a;fytest &#xff08;3&#xff09;pwd #注释&#xff1a;输出/root &#xff08;4&#xff09;docker exec -it wetoband_deploy /bin/bash #注释&#xff1…

基于springboot小区疫情防控系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Python爬虫程序设置代理常见错误代码及解决方法

Python爬虫程序设置代理是爬虫程序中常用的技巧&#xff0c;可以有效地绕过IP限制&#xff0c;提高爬虫程序的稳定性和效率。然而&#xff0c;在设置代理时&#xff0c;常会出现各种错误代码&#xff0c;这些错误代码可能会影响程序的正常运行&#xff0c;甚至导致程序崩溃。本…

12款最火的AI画图软件,助你探索创新设计

ChatGPT火爆出圈&#xff0c;AI画图软件也如雨后春笋般流行起来。各类AI画图的软件工具横空出世&#xff0c;设计师与其焦虑工作会不会被人工智能取代&#xff0c;不如践行“工欲善其事必先利其器”&#xff0c;开拓思路&#xff0c;打开格局&#xff0c;好好地探索下如何利用好…

spring boot +vue 博客系统,开源的资源网站

spring boot vue 博客系统&#xff0c;开源的资源网站&#xff08;Aurora前后端分离博客) 体验地址&#xff1a;http://blog.tlzcf.vip/ 相关技术 前端&#xff1a; 样式来自于&#xff1a;hexo的aurora主题基础框架&#xff1a;vue3(前台) vue2(后台)状态管理&#xff1a;…

一个高效、简洁、轻量的一站式研发管理平台,协作一站式

一、开源项目简介 Codes 是一个 高效、简洁、轻量的一站式研发管理平台。包含需求管理&#xff0c;任务管理&#xff0c;测试管理&#xff0c;缺陷管理&#xff0c;自动化测试&#xff0c;cicd 等功能&#xff1b;Codes 帮助企业加速融合研发、测试、运维一体化进程 常态下,刀…

【EI会议征稿】第三届计算机图形学、人工智能与数据处理国际学术会议 (ICCAID 2023)

第三届计算机图形学、人工智能与数据处理国际学术会议 2023 3rd International Conference on Computer Graphics, Artificial Intelligence and Data Processing (ICCAID 2023) 第三届计算机图形学、人工智能与数据处理国际学术会议&#xff08;ICCAID 2023&#xff09;将于…

npm安装心得(依赖库Python及node-sass依赖环境)

在使用vue的开发环境过程中&#xff0c;总会遇到这样哪样的安装或者打包错误&#xff0c; vue运行或打包常见错误如下&#xff1a; 1. npm install时 node-sass npm ERR command failed &#xff08;可能是node.js的版本和node-sass的版本不符&#xff0c;就是卸掉原来的node.…