基础排序算法
插入排序(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;//将元素插入当前位置}}}
实例分析:
冒泡排序(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部分)来组合起来。因为分后的两部分已经是有序的了,所以最后两部分所有元素取完合起来的整个也是有序的。
排序过程图:
代码实现:
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) | 大型数据集,尤其是链表结构 |
如果对排序稳定性有要求,可以选择插入排序、归并排序。如果数据集较小且无序,可以选择冒泡排序、插入排序或选择排序。对于大型数据集,快速排序、归并排序通常效果更好。
相关文章:

基础排序算法
插入排序(insertion sort) 插入排序每次循环将一个元素放置在适当的位置。像抓牌一样。手里的排是有序的,新拿一张牌,与手里的牌进行比较将其放在合适的位置。 插入排序要将待排序的数据分成两部分,一部分有序&#…...

Nginx的反向代理、动静分离、负载均衡
反向代理 反向代理是一种常见的网络技术,它可以将客户端的请求转发到服务器群集中的一个或多个后端服务器上进行处理,并将响应结果返回给客户端。反向代理技术通常用于提高网站的可伸缩性和可用性,并且可以隐藏真实的后端服务器地址。 #user…...

LLM-TAP随笔——大语言模型基础【深度学习】【PyTorch】【LLM】
文章目录 2.大语言模型基础2.1、编码器和解码器架构2.2、注意力机制2.2.1、注意力机制(Attention)2.2.2、自注意力机制(Self-attention)2.2.3、多头自注意力(Multi-headed Self-attention) 2.3、transforme…...

蓝桥杯备赛-上学迟到
上学迟到 P5707 【深基2.例12】上学迟到 - 洛谷 |https://www.luogu.com.cn/problem/P5707 题目介绍 题目描述 学校和 yyy 的家之间的距离为 s 米,而 yyy 以v 米每分钟的速度匀速走向学校。 在上学的路上,yyy 还要额外花费 1010 分钟的时间进行垃圾分…...

基于 MATLAB 的电力系统动态分析研究【IEEE9、IEEE68系节点】
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
2023百度之星 题目详解 公园+糖果促销
2023百度之星题目详解 文章目录 2023百度之星题目详解前言公园问题题目详解 夏日漫步问题问题详情题目详解 前言 这里为大家带来最新的2023百度之星的题目详解,后续还会继续更新,喜欢的小伙伴可以点个关注啦! 公园问题 今天是六一节&#…...
C++ 2019-2022 CSP_J 复赛试题横向维度分析(中)
上文讲解了2019~2022年第一题和第二题。第一题偏数学认知,算法较简单,第二题考查基本数据结构,如队列、栈……和基础算法,如排序、模拟……。 本文继续讲解第三题和第四题。 1. 第三题 1.1 2022 题目: 逻辑表达式…...

基于Spring Boot的IT技术交流和分享平台的设计与实现
目录 前言 一、技术栈 二、系统功能介绍 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 我国科学技术的不断发展,计算机的应用日渐成熟,其强大的功能给人们留下深刻的印象,它已经应用到了人类社会的各个层次的领域&#x…...
智算引领·创新未来 | 2023紫光展锐泛物联网终端生态论坛成功举办
9月21日,紫光展锐在深圳成功举办2023泛物联网终端生态论坛。论坛以“智算引领创新未来”为主题,吸引了来自信通院、中国联通、中国移动、中国电信、金融机构、终端厂商、模组厂商等行业各领域三百多位精英翘楚汇聚一堂,探讨在连接、算力驱动下…...
网络安全技术指南 103.91.209.X
网络安全技术指的是一系列防范网络攻击、保护网络安全的技术手段和措施,旨在保护网络的机密性、完整性和可用性。常见的网络安全技术包括: 防火墙:用于监控网络流量,过滤掉可能包括恶意软件的数据包。 加密技术:用于保…...

用flex实现grid布局
1. css代码 .flexColumn(columns, gutterSize) {display: flex;flex-flow: row wrap;margin: calc(gutterSize / -2);> div {flex: 0 0 calc(100% / columns);padding: calc(gutterSize / 2);box-sizing: border-box;} }2.用法 .grid-show-item3 {width: 100%;display: fl…...

东郊到家app小程序公众号软件开发预约同城服务系统成品源码部署
东郊到家app系统开发,东郊到家软件定制开发,东郊到家小程序APP开发,东郊到家源码定制开发,东郊到家模式系统定制开发 一、上门软件介绍 1、上门app是一家以推拿为主项,个人定制型的o2o平台,上门app平台提…...

kotlin的集合使用maxBy函数报NoSuchElementException
kotlin设定函数 fun test() {listOf<Int>().maxBy { it } } 查看java实现...

Python开发与应用实验2 | Python基础语法应用
*本文是博主对学校专业课Python各种实验的再整理与详解,除了代码部分和解析部分,一些题目还增加了拓展部分(⭐)。拓展部分不是实验报告中原有的内容,而是博主本人自己的补充,以方便大家额外学习、参考。 &a…...

网络安全--防火墙旁挂部署方式和高可靠性技术
目录 一、防火墙 二、防火墙旁挂部署方式 使用策略路由实现 第一步、IP地址配置 第二步、配置路由 第三步、在防火墙上做策略 第四步、在R2上使用策略路由引流 三、防火墙高可靠性技术--HRP 拓扑图 第一步、配置SW1、SW2、FW1、FW2 第二步、进入防火墙Web页面进行配…...
c++最小步数模型(魔板)
C 最小步数模型通常用于寻找两个点之间的最短路径或最少步数。以下是一个基本的 C 最小步数模型的示例代码: #include<bits/stdc.h> using namespace std; const int N 1e5 5; vector<int> G[N]; int d[N]; bool vis[N];void bfs(int s) {queue<i…...
【每日一题Day337】LC460LFU 缓存 | 双链表+哈希表
LFU 缓存【LC460】 请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。 实现 LFUCache 类: LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象int get(int key) - 如果键 key 存在于缓存中,则获取键的值&#x…...

解决老版本Oracle VirtualBox 此应用无法在此设备上运行问题
问题现象 安装华为eNSP模拟器的时候,对应的Oracle VirtualBox-5.2.26安装的时候提示兼容性问题,无法进行安装,具体版本信息如下: 软件对应版本备注Windows 11专业工作站版22H222621eNSP1.3.00.100 V100R003C00 SPC100终结正式版…...

法规标准-UN R48标准解读
UN R48是做什么的? UN R48全名为关于安装照明和灯光标志装置的车辆认证的统一规定,主要描述了对各类灯具的布置要求及性能要求;其中涉及自动驾驶功能的仅有6.25章节【后方碰撞预警信号】,因此本文仅对此章节进行解读 功能要求 …...

自动化和数字化在 ERP 系统中意味着什么?
毋庸置疑,ERP系统的作用是让工作更轻松。它可以集成流程,提供关键分析,确保你的企业高效运营。这些信息可以提高你的运营效率,并将有限的人力资本重新部署到更有效、更重要的需求上。事实上,自动化和数字化是ERP系统最…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...