排序

排序就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作

排序的稳定性

假若有以下数组,数组中存在两个5,这里区分标记

如果排序之后,红色的5仍然在蓝色的5前面,我们就认为该排序是稳定的

稳定

反之如果打乱了原本红色5在前的顺序,我们就认为该排序是不稳定的排序

 不稳定

常见的排序

插入排序

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。在生活中我们玩斗地主的时候,洗牌就是用到了插入排序。

具体流程如下

第一个数据本身不用排序,从第二个数据开始,把前面两个数据看成一组,然后让1和该组的每一个元素进行比较如果找到合适的位置就插入

然后到第三个数据,这里发现已经有序则不进行改动

然后是第四个数据,一样的,把第四个数据和该组内的所有数据比较,然后找到合适的位置插入

后面也同理

对数组排序完成之后我们发现,插入排序是一种稳定的排序

插入排序的特性

1. 元素集合越接近有序,直接插入排序算法的时间效率越高

2. 时间复杂度:O(N^2)(此篇幅里说到时间复杂度代表平均复杂度)

3. 空间复杂度:O(1)

4. 稳定性:稳定

代码实现

 public static void insertSort(int[] array){for (int i = 1; i < array.length; i++) {int temp = array[i];int j = i-1;for (; j >= 0; j--) {if(array[j]>temp){array[j+1] =array[j];}else{break;}}array[j+1]=temp;}}

希尔排序

希尔排序法也叫做,缩小增量法。体现在排序当中就是对待排序列进行分组,每一组内分别排序,然后减少组数,直至减少到为一组,然后整体再进行排序,这样做的好处是,在缩小为一整组之前,带排序列的数据会基本趋近于有序的,这样就可以减小复杂度。

这里有一组待排的数组,我们把数组分为五组,组内数据的间隔为5,然后进行分组排序。

然后再分为两组,组内数据的间隔为2,然后再进行分组排序

可以发现当分量缩小为2的时候,数组内的数据已经基本趋于有序了,这个时候再缩小增量,就是一整组进行排序

代码实现

 public static void shellSort(int[] array){int gap = array.length;while(gap>1){gap/=2;Shell(array,gap);}}private static void Shell(int[] array,int gap){for (int i = gap; i < array.length; i++) {int temp = array[i];int j = i-gap;for (; j >= 0; j-=gap) {if(array[j]>temp){array[j+gap] =array[j];}else{break;}}array[j+gap]=temp;}}

希尔排序的特性

1. 希尔排序是对直接插入排序的优化,当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很 快。这样整体而言,可以达到优化的效果。

2. 时间复杂度:

最好情况:O(N)

平均情况:O(N^1.3) 希尔排序的时间复杂度并不是稳定的,N的1.3次方是Knuth在进行大量的实验和测试得出了结论,所以我们认为希尔排序的时间复杂度是O(N^1.3)

最坏情况:O(N^2)

3. 空间复杂度:O(1)

4. 稳定性:不稳定

选择排序

每一次从待排序的数据元素中选出最小的一个元素,存放在序列的起始位置,放完之后,然后再从第二个元素开始找到后面最小的元素,以此循环,直到全部待排序的数据元素排完。

我们要对这组数据进行选择排序,先找第一个最小的数据,这里最小的数据为1,然后我们交换1 和 4

然后从第二个位置往后,再找最小的数据,最小数据为2,2 和 6交换

以此往复,得到结果

代码实现

这里的selectSort2是另一种选择排序的思路

 public static void selectSort(int[] array){for (int i = 0; i < array.length; i++) {int minIndex = i;for (int j = i+1; j < array.length; j++) {if(array[j]<array[minIndex]){minIndex = j;}}swap(array,i,minIndex);}}public static void selectSort2(int[] array){int left = 0 ;int right = array.length-1;while(left<right){int minIndex = left;int maxIndex = left;for (int i = left+1; i <=right; i++) {if(array[i]<array[minIndex]){minIndex = i;}if(array[i]>array[maxIndex]){maxIndex = i;}}swap(array,left,minIndex);if(maxIndex==left){maxIndex = minIndex;}swap(array,right,maxIndex);left++;right--;}}private static void swap(int[] array,int a,int b){int temp = array[a];array[a] = array[b];array[b] = temp;}

选择排序的特性

1. 直接选择排序思考非常好理解,但是效率不是很好,实际中很少使用

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1)

4. 稳定性:不稳定

堆排序

前面了解堆这种数据结构的时候提到过堆分为大根堆和小根堆,这里要说到的堆排序就是基于大根堆和小根堆的特性来实现的。如果要求数据从小到大排序就建立大根堆,反之小根堆。

流程为:将一组数据建堆,这里以从小到大的排序为目标,建立一个大根堆,然后把堆顶元素和最后的元素进行交换,交换完成之后对堆顶进行向下调整,然后缩小调整的范围,这样堆的最后一个元素就是最大的元素了。

这里画图举例,假若有一组数据为 1  6  2  4  10  9  3,对这组数据建立大根堆

然后交换堆顶元素和数组的最后一个元素

交换完成之后我们缩小调整的范围,这样10就不会受到后面调整的影响了,这里用红圈标起来

调整为大根堆

然后再交换堆顶元素和最后一个元素

再对堆进行调整

以此往复

代码实现

public static void heapSort(int[] array){createBigHeap(array);int end = array.length-1;while(end>0){swap(array,0,end);siftDown(array,0,end);end--;}}private static void createBigHeap(int[] array){for(int parent = (array.length-1-1)/2;parent>=0;parent--){siftDown(array,parent,array.length);}}private static void siftDown(int[] array,int parent,int end){int child=parent*2+1;while(child<end){if(child+1<end&&array[child+1]>array[child]){child++;}if(array[child]>array[parent]){swap(array,child,parent);parent = child;child= parent*2 +1;}else{break;}}}

堆排序的特性

1. 堆排序使用堆来选数,效率就高了很多。

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(1)

4. 稳定性:不稳定

冒泡排序

冒泡排序很简单,这里不细细展开

代码实现

这里进行了一点优化,可以减小复杂度

 public static void bubbleSort(int[] array) {for (int i = 0; i < array.length; i++) {boolean flag = false;//标记for (int j = 0; j < array.length-i-1; j++) {if(array[j]>array[j+1]){swap(array,j+1,j);flag=true;//如果走不到这一步}}if(flag==false){//说明已经有序,则从这里退出方法return ;}}}

冒泡排序的特性

1. 冒泡排序是一种非常容易理解的排序

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1)

4. 稳定性:稳定

快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元 素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有 元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

快速排序的核心围绕着定基准来进行

先说说第一种方法:Hoare法

以第一个数据为基准,然后定义两个下标,先移动右下标,找到比key小的元素就停止,然后到左下标,移动左下标,找到比key大的元素就停止。

这里找到了9比6大,5比6小,然后交换两个元素。

继续移动,先右再左,找到目标

然后交换,先移动右下标

当左右下标相遇时停止,让left或者right下标元素和最左边的元素交换

此时发现以6为基准,6的左边所有的元素都小于6,6右边的所有元素都大于6

然后在把数组分为两个部分,左边的一组再以4为基准来定基准,右边的一组再以8为基准来定基准以此循环,最终达到排序的效果。

第二种方法:挖坑法

同样的顺序,先移动右边,遇到比key小的元素停下

然后把5挖起来盖住左下标的位置

然后再移动左下标,找到比6大的元素

然后挖起来放到右下标的位置

然后右下标

然后左下标

然后右下标

当左右下标相遇时,把key放入相遇的位置

第三种方法:前后指针法

定义两个下标,

然后按照以下规则移动和交换

取左边下标为key,这里是6,如果J下标的元素小于key,移动I下标,如果I下标和J下标重合,则继续移动J下标,直至不满足条件位置,最后I下标和左边的元素交换即可。

可以发现三种方法定基准的左右数据都把一样,这里更加推荐使用挖坑法进行定基准

代码实现

 private static int partition2(int[] array,int left ,int right) {//Hoare交换法求基准int key = array[left];//选left下标的数作为基准int i = left;//记录下左边下标while(left<right){while(left<right && array[right]>=key){//多加个判断防止越界right--;//没遇到比key小的就往前走}while(left<right && array[left]<=key){left++;//没遇到比key大的就往后走}swap(array,left,right);//遇到大的在前,小的再后,此时就可以交换两个下标的值}swap(array,i,right);//相遇之后交换基准和相遇的地方return left;//返回基准,这样就可以做到,调整顺序,和找基准}private static int partition(int[] array,int left ,int right) {//挖坑法int key = array[left];//选left下标的数作为基准while(left<right){while(left<right&&array[right]>key){right--;}array[left] = array[right];while(left<right&&array[left]<key){left++;}array[right] = array[left];}array[left]=key;return left;//挖坑法的优先度更高,因为会省去交换的操作,从而达到减小复杂度的效果}private static int partition3(int[] array,int left,int right){//前后指针法int front = left;int rear = left +1;while(rear<=right){if(array[rear]<array[left]&&array[++front]!=array[rear]){swap(array,rear,front);}rear++;}swap(array,front,left) ;return front;}

这里有一种特殊的情况,如果一组数据为 1 2 3 4 5 6 7  这样有序或者趋于有序的数据,此时还将左边的第一个数据作为基准,就会使数据变成一颗单分支的二叉树结构,此时的时间复杂度会增大,所以我们为了避免这样的情况,这里需要尽可能的使基准定到数组中间的位置。

public static void quickSort(int[] array) {quick(array,0,array.length-1);}private static void quick(int[] array,int start,int end ){if(start>=end){return ;}int index = midOfThree(array,start,end);swap(array,index,start);int pivot = partition(array,start,end);quick(array,start,pivot-1);quick(array,pivot+1,end);}private static int midOfThree(int[] array, int left , int right){//三数取中,优化基准的位置int mid = (left+right)/2;if (array[left] < array[right]) {if(array[mid]<array[left]){return left;}else if(array[mid]>array[right]){return right;}else{return mid;}}else{if(array[mid]>array[left]){return left;}else if(array[mid]<array[right]){return right;}else{return mid;}}}

快速排序的特性

1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)

4. 稳定性:不稳定

归并排序

归并排序是一种二叉树结构的排序,核心思想就是把一组数据分成多分,然后再合并成有序的数组

代码实现

public static void mergeSort(int[] array) {mergeSortFunction(array,0,array.length-1);}private static void mergeSortFunction(int[] array , int left ,int right) {if(left >=right){return ;}int mid = (left + right )/2;mergeSortFunction(array,left,mid);mergeSortFunction(array,mid+1,right);merge(array,left,right,mid);}private static void merge(int[] array,int left , int right , int mid) {int[] tempArray = new int[right-left+1];int s1 = left;int s2 = mid +1 ;int i = 0 ;while(s1<=mid&&s2<=right){if(array[s1]>=array[s2]){tempArray[i] = array[s2];i++;s2++;}else{tempArray[i] = array[s1];i++;s1++;}}while (s1<=mid){tempArray[i]=array[s1];i++;s1++;}while (s2<=right){tempArray[i]=array[s2];i++;s2++;}for (int j = 0; j < tempArray.length; j++) {array[j+left] = tempArray[j];}}

归并排序的特性

1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(N)

4. 稳定性:稳定

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

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

相关文章

《Node.js与 Elasticsearch的全文搜索架构解析》

文档数量跨越百万级门槛,传统数据库的查询方式就像在没有索引的图书馆里逐架翻书,不仅耗费时间,更难以捕捉文字背后的深层关联。此时,由Node.js与Elasticsearch共同构建的全文搜索系统,便成了梳理信息脉络的无形之手——它能在毫秒之间,从海量文档中识别用户的真实意图,…

Python人工智能matplotlib中markers属性介绍

在 Matplotlib 中&#xff0c;marker 用于标记数据点&#xff0c;可通过多种参数自定义样式。以下是详细说明及示例&#xff1a; 1. 基础设置常用 marker 类型&#xff1a; . : 点 , : 像素 o : 圆圈 v : 下三角形 ^ : 上三角形 < : 左三角形 >…

【Mac】MLX:Lora微调工作流

本文详细介绍如何在Mac电脑上使用Apple的MLX框架&#xff0c;通过LoRA&#xff08;低秩适配&#xff09;技术对大语言模型&#xff08;如Qwen3-4B-Instruct&#xff09;进行微调。以下流程适用于8月9日的Mac mini M4 16GB&#xff0c;涵盖模型获取、数据准备、微调、运行及模型…

润乾报表、帆软报表的开源替代品—JimuReport(积木报表)

国产报表工具选型指南&#xff1a;润乾报表 vs 积木报表&#xff08;JimuReport&#xff09; 如果你在寻找润乾报表、帆软报表的替代产品&#xff0c;JimuReport&#xff08;积木报表&#xff09;是一个值得考虑的选择。它不仅功能全面&#xff0c;而且操作简单&#xff0c;非常…

Tiger任务管理系统-12

今天整了一个老虎网站介绍这套任务管理开源系统&#xff0c;防止链接丢失&#xff0c;体验了一把AI编程&#xff0c;虽说确实省了很多事&#xff0c;但源码确实不敢恭维&#xff0c;尤其是修改的时候&#xff0c;真心累&#xff0c;所以还是要自己掌握核心&#xff0c;AI一时爽…

智慧农业-无人机视角庄稼倒伏农作物倒伏识别分割数据集labelme格式541张1类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件)图片数量(jpg文件个数)&#xff1a;541标注数量(json文件个数)&#xff1a;541标注类别数&#xff1a;1标注类别名称:["fall"]每个类别标注的框数&#xff1a;fall co…

电子电气架构 --- 电气/电子架构迁移已拉开帷幕

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

PPT漏斗图,让数据更美观!

PPT漏斗图制作全攻略&#xff1a;从入门到精通的实用技巧和模板推荐 无论你是职场新人还是PPT老手&#xff0c;在做数据报告或者展示项目进度的时候&#xff0c;你总觉得图表太单调&#xff0c;数据太复杂吗&#xff1f;这时&#xff0c;一张逻辑清晰、结构简单的漏斗图&#…

深入解析C++流运算符(>>和<<)重载:为何必须使用全局函数与友元机制

目录 一、为什么需要重载为全局函数 成员函数重载的问题 全局函数的优势 二、实现细节 1、输出运算符<<的重载 关键部分详解 1. 类定义部分 2. 运算符重载实现 3. main函数中的使用 为什么这样设计&#xff1f; 执行流程 输出结果 2、输入运算符>>的重…

ENS-317 Modbus TCP / 通用模式网关

在工业自动化的复杂网络中&#xff0c;以太网设备与串口设备的 “语言不通” 常常成为数据流转的阻碍。上海泗博自动化推出的 ENS-317 Modbus TCP / 通用模式网关&#xff0c;以强大的协议转换能力、灵活的配置方式和工业级可靠性&#xff0c;为设备互联提供一站式解决方案&…

AcWing 6478. 谁进线下了?III

原题链接 6478. 谁进线下了&#xff1f;III - AcWing题库 这是一道睿抗&#xff08;省赛&#xff09;题 一开始睿抗是啥都不知道 然后一看是省赛吓得我不轻 但读完题简简单单 一道很水的模拟题&#xff08;谁能解释一下睿抗啥意思&#xff09; 一起开康康 题目 Xepa Le…

openpnp - 不连接设备,只大概测试一下摄像头是否好使

文章目录openpnp - 不连接设备&#xff0c;只大概测试一下摄像头是否好使概述笔记备注备注ENDopenpnp - 不连接设备&#xff0c;只大概测试一下摄像头是否好使 概述 顶部相机摄像头在拆装过程中&#xff0c;可能被手上的静电打坏了。 现在和电脑连接是正常的&#xff0c;但是…

使用Python提取PDF大纲(书签)完整指南

&#x1f50d; 一、PDF大纲简介&#x1f4cc; ​PDF大纲&#xff08;Outline&#xff09;​​ 是PDF文档中的导航结构&#xff0c;通常显示在阅读器的侧边栏中&#xff0c;方便用户快速跳转到文档的不同部分。大纲通常以层级结构组织&#xff0c;包含标题和对应的页面位置。本文…

第39周——训练自己的数据集

目录 1. 下载数据 2. 配置开发环境 3. 预处理数据 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 1. 下载数据 百度网盘&#xff1a;百度网盘 请输入提取码 压缩文件中有两个文件夹&#xff0c;分别是Annot…

CentOS7中Docker的安装与卸载

CentOS7 从零开始:Docker 安装与卸载全指南(新手友好版) 作为一名刚接触 Linux 和容器技术的新手,你是否曾在安装 Docker 时被各种命令和报错搞得一头雾水?比如执行 yum install docker 时提示 “仓库不存在”,或者启动 Docker 后用 docker version 只显示 client 不显示…

解决MinIO上传图片后返回URL无法访问的问题

一、问题现象 上传接口返回了文件的访问路径&#xff0c;比如&#xff1a; http://127.0.0.1:9005/lease/20250808/xxx-uuid.png但是用浏览器直接打开该地址却显示权限拒绝,前端也访问不到:二、问题原因分析 桶权限设置不正确: MinIO默认桶权限是私有的&#xff0c;即使浏览器能…

系统网络端口安全扫描脚本及详解

#!/bin/bash # 系统服务端口安全扫描 - 修正版echo " 系统服务端口安全扫描报告 "# 1. 高风险端口识别 echo "⚠️ 对外开放的高风险端口:" awk /0.0.0.0:21/ {print " 端口 21 - FTP (明文传输)\n &#x1f6a8; 严重安全风险&#xff0c;建议…

DAY 39 图像数据与显存

知识点回顾 图像数据的格式&#xff1a;灰度和彩色数据模型的定义显存占用的4种地方 模型参数梯度参数优化器参数数据批量所占显存神经元输出中间状态 batchisize和训练的关系 一、 图像数据的介绍 1.1 灰度图像 从这里开始我们进入到了图像数据相关的部分&#xff0c;也是默认…

从大数据视角理解时序数据库选型:为何选择 Apache IoTDB?

目录一、什么是时序数据库&#xff1f;为什么你需要它&#xff1f;&#x1f527;典型应用场景&#xff1a;二、时序数据库选型维度有哪些&#xff1f;三、为什么推荐 Apache IoTDB&#xff1f;&#x1f9e0; Apache 顶级项目&#xff0c;工业 IoT 场景原生支持&#x1f680; 性…

[ MySQL 数据库 ] 环境安装配置和使用

目录 一. 数据库(DataBase) 1.定义: 2. 常见的数据库产品&#xff1a; 3. MySQL数据库 (1). 介绍 : (2). cmd命令行方式连接 MySQL (3). MySQL的常用命令 二. MySQL数据库 环境安装及配置 三. SQL 1.定义 : 2. DDL (1)数据库 (2)数据表 1. 字段(列)和记录(行) 2. 表特征 3.…