排序方法总结

  1. 排序数组
    给你一个整数数组 nums,请你将该数组升序排列。
    示例 1:
    输入:nums = [5,2,3,1]
    输出:[1,2,3,5]

排序方法总结

    • 「冒泡排序 bubble sort」
    • 「选择排序 selection sort」
    • 「插入排序 insertion sort」
    • 「快速排序 quick sort」
    • 「归并排序 merge sort」
    • 「堆排序 heap sort」

「冒泡排序 bubble sort」

通过连续地比较与交换相邻元素实现排序。这个过程就像气泡从底部升到顶部一样,因此得名冒泡排序。
内外循环的条件非常重要,一定要写对。数组的尾部是最先有序的,要特别注意。设数组的长度为 n

  1. 首先,对 n 个元素执行“冒泡”,将数组的最大元素交换至正确位置。
  2. 接下来,对剩余 n−1 个元素执行“冒泡”,将第二大元素交换至正确位置。
  3. 以此类推,经过 n−1 轮“冒泡”后,前 n−1 大的元素都被交换至正确位置。
  4. 仅剩的一个元素必定是最小元素,无须排序,因此数组排序完成。
// 冒泡排序
class Solution {public int[] sortArray(int[] nums) {int size = nums.length;// 外循环:未排序区间为 [0, i]for(int i = size-1; i > 0 ; i--){int flag = 0;// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端for(int j = 0; j < i; j++){if(nums[j] > nums[j+1]){int tmp = nums[j];nums[j] = nums[j+1];nums[j+1] = tmp;// 如果顺序还是不对,就置标志位。flag = 1;}}if(flag == 0)  break;}return nums;}
}

「选择排序 selection sort」

工作原理非常简单:开启一个循环,每轮从未排序区间选择最小的元素,将其放到已排序区间的末尾。
设数组的长度为 n ,初始状态下,所有元素未排序,即未排序(索引)区间为 [0,n−1] 。

  1. 选取区间 [0,n−1] 中的最小元素,将其与索引 0 处的元素交换。完成后,数组前 1 个元素已排序。
  2. 选取区间 [1,n−1] 中的最小元素,将其与索引 1 处的元素交换。完成后,数组前 2 个元素已排序。
  3. 以此类推。经过 n−1 轮选择与交换后,数组前 n−1 个元素已排序。
  4. 仅剩的一个元素必定是最大元素,无须排序,因此数组排序完成。
// 选择排序
class Solution {public int getMinIndex(int[] nums, int start, int end){int res = nums[start];int index = start;for(int i = start; i < end; i++){if(res > nums[i]){res = nums[i];index = i;}}return index;}private void swap(int[] nums, int a, int b){int tmp = nums[a];nums[a] = nums[b];nums[b] = tmp;}public int[] sortArray(int[] nums) {for(int i = 0; i < nums.length; i++){// 查找[i,nums.length]之间的最小的数,并放到i的位置。int minIn = getMinIndex(nums, i, nums.length);swap(nums, i, minIn);}return nums;}
}

「插入排序 insertion sort」

一种简单的排序算法,它的工作原理与手动整理一副牌的过程非常相似。
具体来说,我们在未排序区间选择一个基准元素,将该元素与其左侧已排序区间的元素逐一比较大小,并将该元素插入到正确的位置。
设基准元素为 base ,我们需要将从目标索引到 base 之间的所有元素向右移动一位,然后将 base 赋值给目标索引。

  1. 初始状态下,数组的第 1 个元素已完成排序。
  2. 选取数组的第 2 个元素作为 base ,将其插入到正确位置后,数组的前 2 个元素已排序。
  3. 选取第 3 个元素作为 base ,将其插入到正确位置后,数组的前 3 个元素已排序。
  4. 以此类推,在最后一轮中,选取最后一个元素作为 base ,将其插入到正确位置后,所有元素均已排序。

虽然冒泡排序、选择排序和插入排序的时间复杂度都为 n^2 ,但在实际情况中,插入排序的使用频率显著高于冒泡排序和选择排序,主要有以下原因。

  • 冒泡排序基于元素交换实现,需要借助一个临时变量,共涉及 3 个单元操作;插入排序基于元素赋值实现,仅需 1 个单元操作。因此,冒泡排序的计算开销通常比插入排序更高。
  • 选择排序在任何情况下的时间复杂度都为 n^2 。如果给定一组部分有序的数据,插入排序通常比选择排序效率更高。
  • 选择排序不稳定,无法应用于多级排序。
// 插入排序
class Solution {public int[] sortArray(int[] nums) {// 外循环:前i个已经排序。for(int i = 1; i < nums.length; i++){// 寄存nums[i]值int tmp = nums[i];int j = i - 1;// 将位置i的元素插入已排好队的数组中,涉及到字移动,倒序遍历while(j >= 0 && nums[j] > tmp){nums[j + 1] = nums[j];j--;}nums[j+1] = tmp;}return nums;}
}

「快速排序 quick sort」

一种基于分治策略(log(n))的排序算法,运行高效,应用广泛。
快速排序的核心操作是“哨兵划分”,其目标是:选择数组中的某个元素作为“基准数”,将所有小于基准数的元素移到其左侧,而大于基准数的元素移到其右侧。

  1. 选取数组最左端元素作为基准数,初始化两个指针 i 和 j 分别指向数组的两端。
  2. 设置一个循环,在每轮中使用 i(j)分别寻找第一个比基准数大(小)的元素,然后交换这两个元素。
  3. 循环执行步骤 2. ,直到 i 和 j 相遇时停止,最后将基准数交换至两个子数组的分界线。

具体的排序过程:

  • 首先,对原数组执行一次“哨兵划分”,得到未排序的左子数组和右子数组。
  • 然后,对左子数组和右子数组分别递归执行“哨兵划分”。
  • 持续递归,直至子数组长度为 1 时终止,从而完成整个数组的排序。
class Solution {private void swap(int[] nums, int start, int end){int tmp = nums[start];nums[start] = nums[end];nums[end] = tmp;}// 左闭右闭的原则private int partition(int[] nums, int start, int end){// 以nums[start]为基准数。这个基准数可以随便选// 尽量要使这个基准数是一个中位数。int base = nums[start];int i = start;int j = end;while(i < j){while(i < j && nums[j] >= base)j--;while(i < j && nums[i] <= base)i++;swap(nums, i, j);}swap(nums, start, i);  // 将基准数交换至两子数组的分界线return i;}private void quickSort(int[] nums, int start, int end){if(start >= end)    return;// base值划分int prvot = partition(nums, start, end);// 分别递归quickSort(nums, start, prvot-1);quickSort(nums, prvot+1, end);}public int[] sortArray(int[] nums) {quickSort(nums, 0, nums.length-1);return nums;}
}

「归并排序 merge sort」

一种基于分治策略的排序算法,包含“划分”和“合并”阶段。

  1. 划分阶段:通过递归不断地将数组从中点处分开,将长数组的排序问题转换为短数组的排序问题。
  2. 合并阶段:当子数组长度为 1 时终止划分,开始合并,持续地将左右两个较短的有序数组合并为一个较长的有序数组,直至结束。

归并排序与二叉树后序遍历的递归顺序是一致的。

  • 后序遍历:先递归左子树,再递归右子树,最后处理根节点。
  • 归并排序:先递归左子数组,再递归右子数组,最后处理合并。
class Solution {// 关键的排序逻辑实现private void merge(int[] nums, int start, int mid, int end){// 左子数组区间为 [left, mid], 右子数组区间为 [mid+1, right]// 创建一个临时数组 tmp ,用于存放合并后的结果int[]  tmp = new int[end - start + 1];int i = start;int j = mid + 1;int k = 0;// 当左右子数组都还有元素时,进行比较并将较小的元素复制到临时数组中(排序的过程)while(i <= mid && j <= end){if(nums[i] <= nums[j])tmp[k++] = nums[i++];elsetmp[k++] = nums[j++];}// 将左子数组和右子数组的剩余元素复制到临时数组while(i <= mid)tmp[k++] = nums[i++];while(j <= end)tmp[k++] = nums[j++];// 将临时数组tmp中的元素复制回nums的对应区间for(k = 0; k < tmp.length; k++){nums[start + k] = tmp[k];}}// 左闭右开private void mergeSort(int[] nums, int start, int end){// 终止条件if(start >= end)  return;int mid = (end - start) / 2 + start;// 左mergeSort(nums, start, mid);// 右mergeSort(nums, mid+1, end);merge(nums, start, mid, end);}// 左闭右闭public int[] sortArray(int[] nums) {mergeSort(nums, 0, nums.length-1);return nums;}
}

「堆排序 heap sort」

一种基于堆数据结构实现的高效排序算法。我们可以利用已经学过的“建堆操作”和“元素出堆操作”实现堆排序。
(使用数组实现大/小顶堆)l = 2 * i + 1; r = 2 * i + 2;

  1. 输入数组并建立小顶堆,此时最小元素位于堆顶。
  2. 不断执行出堆操作,依次记录出堆元素,即可得到从小到大排序的序列。

Queue minHeap = new PriorityQueue<>(); 堆=优先队列

设数组的长度为 n

  1. 输入数组并建立大顶堆。完成后,最大元素位于堆顶。
  2. 将堆顶元素(第一个元素)与堆底元素(最后一个元素)交换。完成交换后,堆的长度减 1 ,已排序元素数量加 1 。
  3. 从堆顶元素开始,从顶到底执行堆化操作(sift down)。完成堆化后,堆的性质得到修复。
  4. 循环执行第 2 步和第 3 步。循环 n−1 轮后,即可完成数组排序。

「堆 heap」是一种满足特定条件的完全二叉树,主要可分为两种类型

  • 「小顶堆 min heap」:任意节点的值 ≤ 其子节点的值。
  • 「大顶堆 max heap」:任意节点的值 ≥ 其子节点的值。
// 堆排序
class Solution {// 堆化操作/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */private void siftDown(int[] nums, int n, int i){while(true){// 获取当前节点的左右子节点int l = 2 * i + 1;int r = 2 * i + 2;int my = i;// 大顶堆,下列的两种情况不符合条件if(l < n && nums[l] > nums[my])my = l;if(r < n && nums[r] > nums[my])my = r;// 若节点 i 最大或索引 l, r 越界,则无须继续堆化,跳出    if(my == i)break;int tmp = nums[i];nums[i] = nums[my];nums[my] = tmp;// 循环向下堆化i = my;}}private void heapSort(int[] nums){// 保证sift内的值不越界。for(int i = nums.length/2-1; i >= 0; i--){siftDown(nums, nums.length, i);}for(int i = nums.length-1; i > 0; i--){// 交换根节点和最右叶子节点(即交换首位元素)int tmp = nums[0];nums[0] = nums[i];nums[i] = tmp;// 堆的长度为 i ,从节点 0 开始,从顶至底堆化siftDown(nums, i, 0);}}public int[] sortArray(int[] nums) {heapSort(nums);return nums;}
}

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

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

相关文章

【非比较排序】计算排序算法

目录 CountSort计数排序 整体思想 图解分析 代码实现 时间复杂度&优缺分析 CountSort计数排序 计数排序是一种非比较排序&#xff0c;不需要像前面的排序一样去比较。 计数排序的特性总结&#xff1a; 1. 计数排序在数据范围集中时&#xff0c;效率很高&#xff0c;但…

[C++]使用C++实现监控文件是否被修改

软件开发过程中经常会用到配置文件,某些应用场景要求在软件运行时动态修改配置文件,此时就需要监控配置文件是否被修改,下面我们就来看看如何使用C实现这一功能吧 软件开发过程中经常会用到配置文件&#xff0c;某些应用场景要求在软件运行时动态修改配置文件&#xff0c;此时…

微信公众号关键词自动回复

今天主要给大家讲一下如何实现微信公众号关键词的自动回复功能&#xff0c;就如网站的文章而言&#xff0c;进行人机识别&#xff0c;需要关注公众号回复验证码获取到验证码从而展示文章内容&#xff0c;&#xff0c;具体效果如下图。 springboot 2.3.2RELEASE 1、微信公众平台…

什么是高可用架构

一、什么是高可用 在运维中&#xff0c;经常听到高可用&#xff0c;那么什么是高可用架构呢&#xff1f;通俗点讲&#xff0c;高可用就是在服务故障&#xff0c;节点宕机的情况下&#xff0c;业务能够保证不中断&#xff0c;服务正常运行。 举个例子&#xff0c;支付宝&#…

Java学习笔记------包和final

包 包就是文件夹。用来管理各种不同功能的Java类&#xff0c;方便后期代码维护 包名的规则&#xff1a;公司域名反写包的作用&#xff0c;需要全部英文小写&#xff0c;见名知意 例如&#xff1a; package com.jxust.domain public class Student{私有化成员变量构造方法成…

naive-ui-admin BasicTable 列表操作栏显示图标icon

效果图 在使用BasicTable的页面添加引用&#xff0c;这里随便弄了个icon import { GameController } from "vicons/ionicons5" 自定义列 const actionColumn reactive({width: 180,title: "操作",key: "action",fixed: "right",ren…

顺丰科技2024届春季校园招聘常见问题解答及SHL测评题库

顺丰科技2024届春季校园招聘常见问题解答及SHL测评题库 Q&#xff1a;顺丰科技2024届校园招聘面向对象是&#xff1f; A&#xff1a;2024届应届毕业生&#xff0c;毕业时间段为2023年10月1日至2024年9月30日&#xff08;不满足以上毕业时间的同学可以关注顺丰科技社会招聘或…

全面介绍HTML的语法!轻松写出网页

文章目录 heading(标题)paragraph(段落)link(超链接)imagemap(映射)table(表格)list(列表)layout(分块)form(表单)更多输入:datalistautocompleteautofocusmultiplenovalidatepatternplaceholderrequired head(首部)titlebaselinkstylemetascriptnoscript iframe HTML&#xff…

备战蓝桥杯---树形DP基础1

我们先来看几个比较简单的例子来引入&#xff1a; 我们令f[i]表示以i为根节点的子树大小&#xff0c;易得状态转移方程为&#xff1a; f[i]1f[son1]....f[soni]; 我们用DFS即可&#xff0c;下面是大致的模板&#xff1a; 让我们来看看几道题吧&#xff1a; 1.贪心树形DPDFS&…

MapGIS农业信息化解决方案(1)

当前,信息化发展水平已经成为衡量一个国家和地区现代化水平和综合实力的重要标志。推进农业信息化,成为正在经历由传统向现代转型的中国农业必须跨越的门槛。连续多年,中央 1 号文件均提出“农业信息化建设”的目标,提出“整合资源,共建平台,健全农村信息服务体系”;在《…

提升Java IO性能!深入掌握FilterOutputStream类!

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java IO相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

FX110网:2024年1月六大机构货币现货交易量数据出炉

2024年1月&#xff0c;各主要平台的机构货币现货交易量呈半升半降态势&#xff0c;但降幅超过涨幅&#xff0c;六大交易场所的现货日均货币交易量&#xff08;ADV&#xff09;平均环比为-1.42%。其中&#xff0c;Cboe FX、360T和Saxo Bank环比下跌&#xff1b;Euronext FX、FxS…

计算机网络---物理层疑难点总结

疑难点 1&#xff0e;传输媒体是物理层吗?传输媒体和物理层的主要区别是什么? 传输媒体并不是物理层。由于传输媒体在物理层的下面&#xff0c;而物理层是体系结构的第一层&#xff0c;因此有时称传输媒体为0层。在传输媒体中传输的是信号&#xff0c;但传输媒体并不知道所传…

MySQL中的describe关键字

背景 新建mysql表中需要一个描述的字段&#xff0c;本人就是用的describe&#xff0c;结果mybatis插入报错&#xff0c;去掉这个字段后结果正常 结果 检查代码后&#xff0c;认为代码正常&#xff0c;并且字段编写正确&#xff0c;类型也正确&#xff0c;怀疑是数据库这边的…

2024龙年特别篇 -- 魔法指针 之 二级指针 指针数组

哈喽哈喽&#xff0c;它来咯&#xff0c;它来咯&#xff0c;接下来有白子寰给你讲解:二级指针 指针数组 目录 二级指针 二级指针的介绍 一图 KO 二级指针 二级指针的运算 指针数组 概念 指针数组模拟二维数组 整形指针数组 二级指针 二级指针的介绍 在介绍时&#xff0…

如何使用word制作填空题?

填空题也是一种比较高效的复习方式&#xff0c;大脑记忆的本质就是不断地重复&#xff0c;电脑给了我们一些自己认为不可能的事情&#xff0c;创造了必要的条件。 第一步标注出自己要进行标注的文字 可以选用红色字体对其进行标注&#xff0c;后续的标注就采用F4&#xff08;…

网络安全与IP安全网络安全

网络安全与IP安全网络安全 网络安全 是指网络系统的硬件&#xff0c;软件以及系统中的数据收到的保护。 保护的基本属性为&#xff1a;机密性&#xff0c;身份认证&#xff0c;完整性和可用性&#xff1b; 基本特征&#xff1a;相对性&#xff0c;时效性&#xff0c;相关性…

如何操作系统缓冲区减少了磁盘碎片化?

如何操作系统缓冲区减少了磁盘碎片化&#xff1f; 在探讨操作系统如何通过使用缓冲区来减少磁盘碎片化之前&#xff0c;我们需要先了解什么是磁盘碎片化以及它为什么会对我们的电脑性能造成影响。 磁盘碎片化简介 磁盘碎片化发生在计算机硬盘上存储数据的过程中。简单来说&am…

正码,反码,补码,移码数据表示

数据表示 ◆带符号数有下列编码方式&#xff0c;当真值为-45时: 原码:一个数的正常二进制表示&#xff0c;最高位表示符号&#xff0c;数值 0 的源码有两种形式:0 (00000000&#xff09;和-0 (1 0000000) 。-45对应原码为10101101 反码:正数的反码即原码;负数的反码是在原码的基…

一文解读MES软件为企业带来的五大好处,附功能亮点及应用场景

在当今激烈竞争的市场环境下&#xff0c;企业需要不断提升自身的灵活性和适应能力&#xff0c;以更好地应对各种挑战和变化。而MES软件作为一种重要的信息化工具&#xff0c;可以帮助企业提升生产管理水平&#xff0c;提高效率&#xff0c;实现精细化管理&#xff0c;从而增强企…