七大排序算法详解

1.概念

1.排序的稳定性

常见的稳定的排序有三种:直接插入排序,冒泡排序,归并排序

对于一组数据元素排列,使用某种排序算法对它进行排序,若相同数据之间的前后位置排序后和未排序之前是相同的,我们就成这种排序算法具有稳定性

单看单个属性的稳定性并无意义,稳定性主要体现在对具有多个属性的对象进行排序时才有意义
假设一个订单对象有两个属性,分别是下单时间与下单金额:
此时我们有一个需求,就是按照订单金额从高到低排序,若金额相同,则按照下单的先后时间排序

  • 方法一:就是先按照订单金额大小排序,然后把金额相同的订单再次按照时间排序,但是这样就需要进行多次排序
  • 方法二:如果我们先把订单按照下单时间的先后排好序,然后再按照订单金额排序,此时如果我们使用的排序是稳定性的,那么它排序后同样是按照下单顺序先后排列的,此时我们就只需要两次排序

所以排序的稳定性也是非常重要

2.排序分类

1.外部排序(不牵扯元素大小比较)

外部排序主要有,桶排序,计数排序,基数排序,时间复杂度近乎O(n)
这三种排序的集合元素非常大,内存放不下,需要使用外部存储器来存储排序,并且对数据的要求非常严格

2.内部排序(基于比较的方式)

在这里插入图片描述

1.插入排序

⭐直接插入排序(稳定)

1.核心思路

每次从无序区间中选择第一个元素,插入到有序区间的合适位置(相当于打扑克牌码牌的过程),有序区间+1,无序区间-1,直至整个数组有序
在这里插入图片描述
⭐⭐⭐直接插入排序在近乎有序的集合性能上非常好(是因为近乎有序的集合,不需要频繁的去交换),常常作为其他高阶排序的优化手段

2.详细代码
    /*** 直接插入排序* @param nums*/public static void insertSort(int[] nums) {// 有序区间[0,i)// 无序区间[i,n)for (int i = 1; i < nums.length; i++) {for (int j = i; j-1 >= 0; j--) {// 若当前值比前一个位置值还小,交换位置if (nums[j] < nums[j-1]) {swap(nums, j , j-1);}}}}

⭐希尔排序

希尔排序是对插入排序的优化,因为插入排序在近乎有序的数组上性能很好,希尔排序正是利用了这一点

1.核心思路

希尔排序不断地将原数组分为若干个子数组,先将子数组内部调整为有序,不断变大分组的长度,当分组长度为1时(一个元素天然有序),此时进行一次插入排序即可

在这里插入图片描述

2.详细代码
   // 希尔排序public static void shellSort(int[] arr) {int gap = arr.length >> 1;while (gap > 1) {// 先按照gap分组,组内使用插入排序insertionSortByGap(arr,gap);gap = gap >> 1;}// 当gap == 1时,整个数组接近于有序,此时来一个插入排序insertionSortByGap(arr,1);}// 按照gap分组,组内的插入排序private static void insertionSortByGap(int[] arr, int gap) {// i初始化为0也可以,更容易理解for (int i = gap; i < arr.length; i++) {for (int j = i; j - gap >= 0 && arr[j] < arr[j - gap] ; j -= gap) {swap(arr,j,j - gap);}}}

2.选择排序

⭐直接选择排序(不稳定)

1.核心思路

每次在无序区间选择最小值与无序区间第一个位置元素交换,有序区间+1,无序区间-1,直至整个数组有序
在这里插入图片描述

2.详细代码
    /*** 直接选择排序* @param nums*/public static void selectionSort(int[] nums) {// 起始状态:有序区间[0,i)// 无需区间[i,n)for (int i = 0; i < nums.length - 1; i++) {// 指向当前无需区间最小值的下标int minIndex = i;for (int j = i+1; j < nums.length; j++) {// 若当前值比最小值还小if (nums[j] < nums[minIndex]) {// 更新最小值下标minIndex = j;}}// 此时minIndex指向无需区间的最小值,将其加载有序区间的后面,有序区间+1,无序区间-1swap(nums, i, minIndex);}}

⭐堆排序

堆排详情博客:
原地堆排序

3.交换排序

⭐冒泡排序(稳定)

1.核心思路

每次遍历将无序数组的最大元素交换至末尾,无序数组-1,有序数组+1,直至整个数组有序

2.详细代码
    // 无序区间[0...i]// 有序区间[]public static void bubbleSort(int[] arr) {// 外层循环表示要进行元素操作的趟数for (int i = 0; i < arr.length - 1; i++) {boolean isSwaped = false;for (int j = 0; j < arr.length - i - 1; j++) {if (arr[j] > arr[j + 1]) {isSwaped = true;swap(arr,j,j + 1);}}if (!isSwaped) {break;}}}

⭐快速排序(不稳定)

1.核心思路

每次从无序数组中选取一个元素作为分区点(pivot),将原集合中所有<pivot的元素都放在分区点的左侧,将所有>pivot的元素都放在分区点的右侧,这样分区点最终位置就确定了,继续在左半区间和右半区间重复此过程即可
在这里插入图片描述

快速排序和直接选择排序不同的是在快排选择的过程中在不断地调整元素的顺序,在这个过程中原数组已经不断有序了

2.详细代码
    /*** 快速排序(挖坑法)*/public static void quitSort(int[] nums) {quitSortInternal(nums, 0, nums.length-1);}private static void quitSortInternal(int[] nums, int l, int r) {if (l >= r) {return;}// 分区之后,返回已经放好位置的元素下标int p = quitSortByHole(nums, l, r);// 将放好位置元素的左侧丢进去排序quitSortInternal(nums, l, p - 1);// 在将放好位置元素的右侧丢进去排序quitSortInternal(nums, p + 1, r);// 此时数组就整体有序了}/*** 使用非递归的方式* @param nums* @param l* @param r*/private static void quitSortInternal1(int[] nums, int l, int r) {Deque<Integer> stack = new ArrayDeque<>();stack.push(r);stack.push(l);while (!stack.isEmpty()) {// 获取左右区间int i = stack.pop();int j = stack.pop();if (i >= j) {continue;}// 调用获得一个位置的结果int p = quitSortByHole(nums, i, j);// 将左边压入栈中stack.push(p-1);stack.push(i);// 右边压入栈中stack.push(j);stack.push(p+1);}}private static int quitSortByHole(int[] nums, int l, int r) {// 分区数字int pivot = nums[l];int i = l;int j = r;while (i < j) {while (i < j && nums[j] >= pivot) {j--;}// 走到这说明nums[j] < pivotnums[i] = nums[j];while (i < j && nums[i] <= pivot) {i++;}// 走到这说明nums[i] > pivotnums[j] = nums[i];}// 出循环说明i==j// 将pivot写回inums[i] = pivot;// 返回分区点最终位置return i;}

4.归并排序

⭐归并排序(稳定,时间复杂度O(nlogn),空间复杂度O(n))

对原始数据不敏感

1.核心思路

1. 先不断地将原数组一分为二,直至子数组长度为1
2. 不断地将两个相邻的有序子数组合并成一个更大的有序子数组,直至合并后的数组与原数组长度相同,此时排序完成
在这里插入图片描述
核心操作:合并两个子数组merge(nums, l, mid, r)
int i=l代表左边数组走到的下标,
int j=mid+1代表右边数组走到的下标,
k代表当前原数组合并到哪个位置

2.归并排序应用

在这里插入图片描述

3.详细代码
    /*** 归并排序*/public static void mergeSort(int[] nums) {mergeSortInternal(nums, 0, nums.length-1);}/*** 在nums的l-r内进行归并排序* @param nums* @param l* @param r*/private static void mergeSortInternal(int[] nums, int l, int r) {if (l >= r) {return;}int mid = l + ((r - l) >> 1);;// 将左边和右边丢到mergemergeSortInternal(nums, l, mid);mergeSortInternal(nums, mid+1, r);// 此时说明左右两个数组都已经排好序merge(nums, l, mid, r);}private static void merge(int[] nums, int l, int mid, int r) {// 创建一个大小与r-l+1一样大的数组int[] aux = new int[r - l + 1];System.arraycopy(nums, l, aux, 0, r - l + 1);int i = l;int j = mid+1;// i代表左边数组走到的下标,j代表右边数组走到的下标,k代表当前原数组合并到哪个位置for (int k = l; k <= r; k++) {if (i > mid) {// 说明左边的数组已经走完,把右边的全部写回原数组即可nums[k] = aux[j-l];j++;} else if (j > r) {// 说明右边的数组已经走完,把左边的全部写回原数组即可nums[k] = aux[i-l];i++;} else if (aux[i-l] <= aux[j-l]) {// 说明左边的数字小,把左边数组内的数字写回原数组nums[k] = aux[i-l];i++;} else {// 说明右边的数字小,把右边数组内的数字写回原数组nums[k] = aux[j-l];j++;}}}

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

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

相关文章

vue3 vite使用 monaco-editor 报错

报错&#xff1a;Unexpected usage at EditorSimpleWorker.loadForeignModule 修改配置&#xff1a; "monaco-editor-webpack-plugin": "^4.2.0",删除不用 版本&#xff1a; "monaco-editor": "^0.28.1", 修改如下&#xff1a; opti…

stm32 无刷电机 V/F控制(无刷电机变频控制)以及与foc(矢量控制)的区别

无刷电机有三种控制方式&#xff0c;方波控制&#xff0c;foc控制以及变频控制&#xff0c;前两章我们讲解了方波和foc的控制方法&#xff0c;今天我们一起来讲一讲什么是无刷电机的变频控制&#xff08;VF&#xff09;以及变频控制的优势是什么。 实验用的硬件还是KY_Motor的无…

IDEA远程开发

IDEA远程开发 前期准备 IDEA的远程开发是在本地去操昨远程服务器上的代码&#xff0c;所以我们先需要准备一台服务器,在此我使用vmware虚拟出ubuntu-20.04.6的Server版本,以便后面演示。 Ubuntu的Java环境配置 JDK8 sudo apt install openjdk-8-jdkmaven sudo apt instal…

三星申请新商标:未来将应用于智能戒指,作为XR头显延伸设备

三星最近向英国知识产权局提交了名为“Samsung Curio”的新商标&#xff0c;这预示着三星正积极扩展可穿戴设备生态。该商标被分类为“Class 9”&#xff0c;这表明它有可能被用于未来的智能戒指。 据报道&#xff0c;三星计划将智能戒指作为XR头显设备的延伸&#xff0c;与苹果…

面试题-React(六):React组件和生命周期

一、React组件 React组件简介&#xff1a; React组件是构建用户界面的基本单元。它们将界面拆分成独立、可重用的部分&#xff0c;使得代码更加模块化、可维护性更高。React组件可以是函数组件或类组件&#xff0c;它们接收输入的数据&#xff08;称为props&#xff09;并返回…

基于PaddlePaddle实现的声纹识别系统

前言 本项目使用了EcapaTdnn、ResNetSE、ERes2Net、CAM等多种先进的声纹识别模型&#xff0c;不排除以后会支持更多模型&#xff0c;同时本项目也支持了MelSpectrogram、Spectrogram、MFCC、Fbank等多种数据预处理方法&#xff0c;使用了ArcFace Loss&#xff0c;ArcFace loss…

ETLCloud轻量级数据中台解决方案

引言 随着信息时代的到来&#xff0c;数据已经成为企业的重要资源&#xff0c;如何高效地管理、分析和应用数据变得尤为关键。然而&#xff0c;许多企业在构建数据中台时面临着高昂的成本、复杂的架构和漫长的实施周期等问题。为了解决这些挑战&#xff0c;我们推出了ETLCloud…

java八股文面试[java基础]——CGLIB动态代理与JDK动态代理

CGLIB CGLIB简介&#xff1a; 什么是CGLIB CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架&#xff08;Spring、dynaop&#xff09;中&#xff0c;用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架&#xff0c;同样使用CGLIB来代理单端&#xff…

利用LLM模型微调的短课程;钉钉宣布开放智能化底座能力

&#x1f989; AI新闻 &#x1f680; 钉钉宣布开放智能化底座能力AI PaaS&#xff0c;推动企业数智化转型发展 摘要&#xff1a;钉钉在生态大会上宣布开放智能化底座能力AI PaaS&#xff0c;与生态伙伴探寻企业服务的新发展道路。AI PaaS结合5G、云计算和人工智能技术的普及和…

文心一言 VS 讯飞星火 VS chatgpt (81)-- 算法导论7.4 6题

六、如果用go语言&#xff0c;考虑对 PARTITION 过程做这样的修改:从数组 A 中随机选出三个元素&#xff0c;并用这三个元素的中位数(即这三个元素按大小排在中间的值)对数组进行划分。求以a 的函数形式表示的、最坏划分比例为 a:(1-a)的近似概率&#xff0c;其中 0<a<1。…

卡尔曼滤波学习笔记

Kalman Filter Ⅰ、直观理解1、描述2、例子 Ⅱ、适用范围1、线性系统2、噪声服从高斯分布 Ⅲ、相关公式1、原始公式2、预测公式3、更新公式4、初值赋予5、总结 Ⅳ、应用例子Ⅴ、代码实现Ⅵ、公式理解1、协方差矩阵的理解1.1 协方差1.2 协方差矩阵1.3、相关数学公式 2、状态方程…

Android12之ABuffer数据处理(三十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

Ubuntu20.04安装软件报错:The following packages have unmet dependencies

Ubuntu20.04更换阿里云源后安装软件都会报错&#xff1a;The following packages have unmet dependencies 查看资料&#xff0c;大概是ubuntu本身的源比较版本较老&#xff0c;而阿里云的源比较新&#xff0c;因此版本不匹配造成依赖的库不匹配&#xff0c;所以只要将阿里云的…

【网络】HTTPS的加密

目录 第一组&#xff0c;非对称加密第二组&#xff0c;非对称加密第三组&#xff0c;对称加密证书签名 HTTPS使用的是非对称加密加对称加密的方案 &#xff08;非对称加密&#xff1a;公钥加/解密&#xff0c;私钥解/加密&#xff09; &#xff08;对称加密&#xff1a;一组对称…

什么是响应式设计(Responsive Design)?如何实现一个响应式网页?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 响应式设计&#xff08;Responsive Design&#xff09;⭐ 如何实现一个响应式网页&#xff1f;1. 弹性网格布局2. 媒体查询3. 弹性图像和媒体4. 流式布局5. 优化导航6. 测试和调整7. 图片优化8. 字体优化9. 渐进增强10. 面向移动优先11. …

go、java、.net、C#、nodejs、vue、react、python程序问题进群咨询

1、面试辅导 2、程序辅导 3、一对一腾讯会议辅导 3、业务逻辑辅导 4、各种bug帮你解决。 5、培训小白 6、顺利拿到offer

【优选算法】—— 字符串匹配算法

在本期的字符串匹配算法中&#xff0c;我将给大家带来常见的两种经典的示例&#xff1a; 1、暴力匹配&#xff08;BF&#xff09;算法 2、KMP算法 目录 &#xff08;一&#xff09;暴力匹配&#xff08;BF&#xff09;算法 1、思想 2、演示 3、代码展示 &#xff08;二&…

基于Roop视频换脸

Roop 是一个强大的一键换脸工具&#xff0c;允许用户在视频中替换面部&#xff0c;只需要目标面部的一张图片&#xff0c;无需数据集&#xff0c;无需训练。 相对于之前的 Simswap 来说效果要好很多&#xff0c;不过需要注意的是没有授权不要商用。 文章目录 环境搭建使用方法…

Java之AbstractQueuedSynchronizer

要让你写一个java版的并发同步库&#xff0c;你会怎么思考设计&#xff1f;&#xff1f;&#xff1f;先思考三五分钟 请先拜读下老外的paperhttp://gee.cs.oswego.edu/dl/papers/aqs.pdf 1. 简介 AbstractQueuedSynchronizer&#xff0c;简称AQS&#xff0c;中文翻译为抽象队…

Git 原理与使用

1.版本控制器 所谓的版本控制器&#xff0c;就是能让你了解到⼀个⽂件的历史&#xff0c;以及它的发展过程的系统。通俗的讲就是⼀个可以记录⼯程的每⼀次改动和版本迭代的⼀个管理系统&#xff0c;同时也⽅便多⼈协同作业。 ⽬前最主流的版本控制器就是 Git 。Git 可以控制电脑…