【Java算法】八大排序

八大排序算法

目录

注意:以下排序均属于内部排序


排序总结分析表

在这里插入图片描述


一、插入排序

在这里插入图片描述

1. 直接插入排序

(1)整体思路

通过动图可以形象的理解到

说明:(惯用思想)初始时视第一个元素是有序的,之后通过排序逐渐增大有序序列的长度

(2)代码实现

第一种写法:while 循环更规范

public static void insert_sort(int[] arr) {/*插入排序的思想:从无序的序列中拿一个数,通过比较的方式插入到有序序列中初始状态:假设第一个数是有序的,从第二个元素开始,和有序序列比较,然后插入*/// 在无序序列中抽取一张牌for (int i = 1; i < arr.length; i++) {// 记录要插入的元素值,位置位于有序序列的末尾int insertvalue = arr[i];// 在有序序列中从后往前和插入元素比较,找到插入位置int j = i - 1;/*1 2 3 9 10 15 5插入5:需要插入在3的后面。所以只要插入元素比当前比较元素小,就往后移*/// 推荐这种写法,更规范while (j >= 0 && insertvalue < arr[j]) {arr[j + 1] = arr[j]; //  元素后裔j--;}// 插入元素(插入到  比当前插入元素小的 元素  的后面)arr[j + 1] = insertvalue;}
}

第二种写法:使用for 循环

public static void insert_sort_1(int[] arr) {// 第二种写法:使用for循环for (int i = 1; i < arr.length; i++) {int insertvalue = arr[i];int j = i - 1;for (; j >= 0; j--) {if (insertvalue < arr[j]) {arr[j + 1] = arr[j];}else{break; // 如果 insertvalue >= arr[j] 就退出循环}}arr[j + 1] = insertvalue;}
}

2. 折半插入排序

改进点:使用折半查找提高效率,使用循环遍历逐个匹配的效率太差

    // 查找插入位置的方法采用二分思想(由于查找位置的序列本身就是有序的,所以可以使用二分)
public static void binary_insert_sort(int[] arr) {for (int i = 1; i < arr.length; i++) {// 初始时:把第一个元素看成是有序的,然后进行插入排序int insertvalue = arr[i];int left = 0;int right = i - 1; // 和 j = i -1 是等价的while (left <= right) {int mid = left + ((right - left) / 2);if (arr[mid] < insertvalue) {left = mid + 1;} else {right = mid - 1;}}// 找到了插入位置,移动元素为插入做准备// 为了维持稳定性,应该插入到 right 的后边// 插入位置为 right + 1 , 需要把这个位置空出来才可以插入,所以要取等for (int j = i - 1; j >= right + 1; j--) {arr[j + 1] = arr[j]; //元素后移}arr[right + 1] = insertvalue;}
}

3. 希尔排序

动图演示

在这里插入图片描述

使用间隔 gap,gap 逐渐递减,最后 gap 的值必须是一,每一轮排序对 gap 产生的序列进行排序

快速写希尔排序:把直接插入排序中 “ 1 ” 的位置全部替换“ gap ”

/*
快速写希尔排序算法代码:只要把直接插入排序中为 1 的地方全部改成 gap 即可*/
public static void shell_sort(int[] arr){// 增量序列取中间值(常用方法)/*增量序列是递减的,并且最后一个值一定是一*/int gap = arr.length / 2; // 向下取整while (gap >= 1) {shell(arr, gap);gap /= 2;}
}// 一趟写入排序的过程
public static void shell(int[] arr, int gap){// 思想和直接插入排序,不同点就在原来 “加/减一” 的位置全部变成 “gap”// 由于是分组排,这里需要包含分组的第一个元素,所以不加一for (int i = gap; i < arr.length; i++) {int insertvalue = arr[i];int j = i - gap;// 移动元素while(j >= 0 && insertvalue < arr[j]){arr[j + gap] = arr[j];j -= gap;}arr[j + gap] = insertvalue;}
}

二、交换排序

1. 冒泡排序

动图演示

在这里插入图片描述

(1)普通版本

public static void bubble_sort(int[] arr){for (int i = 0; i < arr.length - 1; i++) {for (int j = 0; j < arr.length - 1 - i; j++) {// 前面的比后面大,交换位置if(arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}

(2)改进版本

亮点:通过变量标记的方式标记是否执行了交换操作,可以一定程度上减少比较次数

// 改进版本:如果本身就有序,则无序交换,减少比较次数
public static void bubble_sort_improve(int[] arr){for (int i = 0; i < arr.length - 1; i++) {int flag = 0;  // 每次进入循环都标记为0,如果有序就不交换,flag = 0for (int j = 0; j < arr.length - 1 - i; j++) {// 前面的比后面大,交换位置if(arr[j] > arr[j + 1]){flag = 1; // 交换了就标记为一int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}if(flag == 0){/* 在一趟遍历之后,如果都没有发生交换,说明元素已经有序了,后面的比较没有意义了,直接退出*/break;}}
}

2. 快速排序

动图演示

在这里插入图片描述

主要思想:递归,双指针(对撞指针)

思路分析

 /*快速排序是冒泡排序的改进版本,核心在于递归和双指针思想说明1.选取数组的第一个元素为枢纽2.left,right为数组下标3.延申:可以对任意区间排序*/public static int partition(int[] arr, int left, int right) {/*双指针思想1.left:指向数组的 第一个 元素,从 左往右 找,如果比中间值 大,就搬到后面(high的位置)2.right:指向数组的 最后一个 元素,从 左右往左 找,如果比中间值 小,就搬到前面(left的位置)*/int pivot = arr[left];// 两个指针的移动逐渐靠近,当两个指针重合时,退出循环// 此时指向的位置就是枢纽的位置while (left < right) {/*注意:指针的移动可能会越界,需要加上判断条件 left < right易错点:先找小的,后找大的*/// 首先在后面找小的往前搬(那对立面就是不符合要求,right指针往前移)while (arr[right] >= pivot && left < right) {right--;}arr[left] = arr[right];// 然后在前面找大的往后搬(那对立面就是不符合要求,left指针往后移)while (arr[left] <= pivot && left < right) {left++;}arr[right] = arr[left];}// 此时 left = right,指向中间枢纽的位置,放入枢纽值,返回枢纽的位置arr[left] = pivot;return left;
}public static void quicksort(int[] arr, int left, int right) {/*递归易错的地方:需要有一个递归出口*/if(left < right){int pivot = partition(arr,left,right); // 首先计算枢纽值// 递归递归左子区间quicksort(arr,left,pivot - 1);// 递归排序右子区间quicksort(arr,pivot + 1,right);}
}

三、选择排序

1. 简单选择排序

动图演示

在这里插入图片描述

基本思路:选一个数,在这个数的后面找有没有比本身还小的,有就交换位置

优化点:在后面找一个最小的数,避免重复的覆盖,减少比较次数

区别冒泡排序的优化

(1)普通版本

public static void select_sort(int[] arr){for (int i = 0; i < arr.length; i++) {for (int j = i + 1; j < arr.length; j++){if(arr[j] < arr[i]){int temp = arr[j];arr[j] = arr[i];arr[i] = temp;}}}
}

(2)改进版本

public static void select_sort_improve(int[] arr){// 比较 n-1 趟for (int i = 0; i < arr.length; i++) {int min_index = i; // 假设当前元素是最小的,记录下标// 在当前元素的后面找有没有更小的,有就交换位置for (int j = i + 1; j < arr.length; j++){// 如果找到更小的,就更新下标if(arr[j] < arr[min_index]){min_index = j;}}// 如果最小元素不是本身(找到了更小的),就交换位置if(min_index != i){int temp = arr[i];arr[i] = arr[min_index];arr[min_index] = temp;}}
}

2. 堆排序(二叉堆)

(1)基本介绍

补充:关于树中节点的序号和数组下标的关系

方法:从左到右,从上到下依次标号

图例(对应数组下标

       0/   \1      2/ \    / \3   4  5   6

大根堆示例

       10/    \8      6/ \    / \5   3  2

小根堆示例

       1/    \3      4/ \    / \6   8  9

(2)堆排序思想

堆排序代码

/*
堆排序思想(又叫二叉堆)
分类:大顶堆,小顶堆堆符合二叉树的性质说明:数组的下标在树中是:从上到下,从左到右依次编号的排序过程说明1. 构建一个大顶堆,每次交换最小和最大的,并且堆大小缩小减一,
2. 交换的过程:把最大的放在有序区,但是破坏了大顶堆的结构,需要重新调整堆3. 有序的过程:把最大的放在有序区,数组从后往前一次放入有序元素完成排序*/// 堆调整(大顶堆)
// n:表示数组的大小;i:表示最大值的下标索引
public static void heapify(int[] arr, int n, int i) {/*易错:这里表示的下标值,然而二叉树中的性质指的是物理位置数组是从0开始编号的,举例说明7/   \6     57:下标索引是06:按照物理位置计算方法(左孩子:2 * i = 0),结果还是0,但是下标索引是1得出的关系:在物理位置的基础上加一才是索引下标*/int max_index = i; // 初始化最大值下标索引int left = 2 * i + 1; // 左孩子的下标索引int right = 2 * i + 2; // 右孩子的下标索引// 和左右孩子比较,更新最大值下标索引// 注意:防止越界,需要加上限制条件if (left < n && arr[left] > arr[max_index]) {max_index = left;}if (right < n && arr[right] > arr[max_index]) {max_index = right;}// 如果最大值不是初始化的值,说明找到了更大的值,把最大值放到根节点if (max_index != i) {int temp = arr[i];arr[i] = arr[max_index];arr[max_index] = temp;// 递归调整左右子树(max_index在这个过程中做了更新)heapify(arr, n, max_index);}
}//堆排序
public static void heap_sort(int[] arr) {/*7/   \6     5/ \   / \4   3 2   1总节点数:7循环起点:7/2 - 1 = 3 - 1 = 2,即下标为2的元素开始(元素5)*/// 构建大顶堆(如果每一个子树都是大顶堆,则整个二叉堆就是大顶堆)int n = arr.length;// 从最后一个非叶子节点开始向上进行堆调整for (int i = n / 2 - 1; i >= 0; i--) {heapify(arr, n, i);}// 排序过程:交换元素,调整堆,进行 n - 1 趟排序// 初值:每交换一次,可以理解为排序一个元素,则堆中需要排序的元素总数减少一// 初值为 i -1 正好对应最后一个元素的下标,方便交换for (int i = n - 1; i > 0; i--) {// 把最大的和最小的进行交换int temp = arr[0];arr[0] = arr[i];arr[i] = temp;// 交换后破坏了大顶堆的结构,重新调整堆(排序的过程中堆的大小在递减)heapify(arr, i, 0);}
}

四、归并排序

动图演示

请添加图片描述

思路:运用合并为有序序列的思想、递归思想,两个有序序列通过比较的方式合并成一个更长的有序序列,而比较的过程正好是排序的过程

小结:排序左区间,排序右区间,两个区间合并,然而排序的过程又是两个区间合并的过程,即采用递归思想

归并排序代码



五、基数排序

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

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

相关文章

玩转Docker | 使用Docker部署Qwerty Learner英语单词学习网站

玩转Docker | 使用Docker部署Qwerty Learner英语单词学习网站 前言一、Qwerty Learner简介Qwerty Learner 简介主要特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署Qwerty Learner服务下载Qwerty Learner镜像编辑部署文件创建容器检查容器状态检查服务…

Vue3中computed和watch的区别

文章目录 前言&#x1f50d; 一、computed vs watch✅ 示例对比1. computed 示例&#xff08;适合模板绑定、衍生数据&#xff09;2. watch 示例&#xff08;副作用&#xff0c;如调用接口&#xff09; &#x1f9e0; 二、源码实现原理&#xff08;简化理解&#xff09;1. comp…

C++修炼:C++11(二)

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

单元测试与QTestLib框架使用

一.单元测试的意义 在软件开发中&#xff0c;单元测试是指对软件中最小可测试单元&#xff08;通常是函数、类的方法&#xff09;进行隔离的、可重复的验证。进行单元测试具有以下重要意义&#xff1a; 1.提升代码质量与可靠性&#xff1a; 早期错误检测&#xff1a; 在开发…

(附实现代码)Step-Back 回答回退策略扩大检索范围

1. LangChain 少量示例提示模板 在与 LLM 的对话中&#xff0c;提供少量的示例被称为 少量示例&#xff0c;这是一种简单但强大的指导生成的方式&#xff0c;在某些情况下可以显著提高模型性能&#xff08;与之对应的是零样本&#xff09;&#xff0c;少量示例可以降低 Prompt…

16-Oracle 23 ai-JSON-Relational Duality-知识准备

一直做DBA的小伙伴&#xff0c;是不是对开发相对陌生一些。JSON 关系二元性是 Oracle Database 23ai 中重要的特性&#xff0c;同时带来的是范式革命。JSON关系二元性解决了数据库领域的根本矛盾​&#xff0c;结构化数据的严谨性与半结构化数据的灵活性之间的矛盾。 JSON Rela…

什么是预训练?深入解读大模型AI的“高考集训”

1. 预训练的通俗理解&#xff1a;AI的“高考集训” 我们可以将预训练&#xff08;Pre-training&#xff09; 形象地理解为大模型AI的“高考集训”。就像学霸在高考前需要刷五年高考三年模拟一样&#xff0c;大模型在正式诞生前&#xff0c;也要经历一场声势浩大的“题海战术”…

思尔芯携手Andes晶心科技,加速先进RISC-V 芯片开发

在RISC-V生态快速发展和应用场景不断拓展的背景下&#xff0c;芯片设计正面临前所未有的复杂度挑战。近日&#xff0c;RISC-V处理器核领先厂商Andes晶心科技与思尔芯&#xff08;S2C&#xff09;达成重要合作&#xff0c;其双核单集群AX45MPV处理器已在思尔芯最新一代原型验证系…

vscode配置lua

官网下载lua得到如下 打开vscode的扩展下载如下三个 打开vscode的此处设置 搜索 executorMap&#xff0c;并添加如下内容

理解 RAG_HYBRID_BM25_WEIGHT:打造更智能的混合检索增强生成系统

目录 理解 RAG_HYBRID_BM25_WEIGHT&#xff1a;打造更智能的混合检索增强生成系统 一、什么是 Hybrid RAG&#xff1f; 二、什么是 RAG_HYBRID_BM25_WEIGHT&#xff1f; 三、参数设置示例 四、什么时候该调整它&#xff1f; 五、实战建议 六、总结 理解 RAG_HYBRID_BM25…

Spring Boot 2 中 default-autowire 的使用

Spring Boot 2 中 default-autowire 的使用 在 Spring Boot 2 中&#xff0c;default-autowire 这个来自传统 XML 配置的概念仍然存在&#xff0c;但它的使用已经大大减少&#xff0c;因为现代 Spring Boot 应用主要使用注解驱动的配置方式。 default-autowire 在 Spring Boo…

Spring Boot + Thymeleaf 防重复提交

在 Spring Boot 与 Thymeleaf 结合的 Web 应用中&#xff0c;防止重复提交可以采用token 机制 客户端禁用按钮的方式实现&#xff0c;在高并发场景下&#xff0c;考虑使用 Redis 存储 token 而非 Session。 第一步&#xff1a;后端实现 Controller public class FormControl…

【20250607接单】Spark + Scala + IntelliJ 项目的开发环境配置从零教学

本教程适用于零基础、一台刚装好 Windows 的全新电脑开始&#xff0c;搭建能运行 Spark Scala IntelliJ 项目的开发环境。以下是超详细、小白级别逐步教程&#xff0c;从“下载什么”到“点击哪里”都帮你列清楚。 &#x1f3af; 目标 操作系统&#xff1a;Windows10/11工具…

【ubuntu】虚拟机安装配置,sh脚本自动化,包含 apt+时间同步+docker+mysql+redis+pgsql

可以说是ubuntu基础环境搭建合集&#xff0c;个人学习用&#xff0c;使用sh一键安装&#xff0c;避免复制各种命令 流程主要包括 0. 可选择不同ubuntu版本对应安装&#xff08;支持 Ubuntu 20.04/22.04/23.04/24.04&#xff09; 1. apt换源aliyun 2. 时间选择上海时区&#x…

Rust 学习笔记:关于智能指针的练习题

Rust 学习笔记&#xff1a;关于智能指针的练习题 Rust 学习笔记&#xff1a;关于智能指针的练习题问题一问题二问题三问题四问题五问题六问题七问题八问题九问题十问题十一 Rust 学习笔记&#xff1a;关于智能指针的练习题 参考视频&#xff1a; https://www.bilibili.com/vi…

JavaScript ES6 解构:优雅提取数据的艺术

JavaScript ES6 解构&#xff1a;优雅提取数据的艺术 在 JavaScript 的世界中&#xff0c;ES6&#xff08;ECMAScript 2015&#xff09;的推出为开发者带来了许多革命性的特性&#xff0c;其中“解构赋值”&#xff08;Destructuring Assignment&#xff09;无疑是最受欢迎的功…

Shell 命令及运行原理 + 权限的概念(7)

文章目录 Shell 命令以及运行原理&#xff08;4-1.22.08&#xff09;Linux权限的概念1. 什么是权限2. 认识人&#xff08;普通用户&#xff0c;root用户&#xff09;以及两种用户的切换认识普通用户和root用户两种用户之间的切换指令提权 3. 文件的属性解析 权限属性指令ll显示…

以智能管理为基础,楼宇自控打造建筑碳中和新路径

在全球气候变化的严峻形势下&#xff0c;“碳中和”已成为各国发展的重要战略目标。建筑行业作为能源消耗与碳排放的“大户”&#xff0c;其运行阶段的能耗占全社会总能耗近40%&#xff0c;碳排放占比与之相当&#xff0c;实现建筑碳中和迫在眉睫。传统建筑管理模式下&#xff…

Python爬虫实战:研究Hyper 相关技术

一、项目概述 本项目展示了如何结合 Python 的异步编程技术与 Hyper 框架开发一个高性能、可扩展的网络爬虫系统。该系统不仅能够高效地爬取网页内容,还提供了 RESTful API 接口,方便用户通过 API 控制爬虫的运行状态和获取爬取结果。 二、系统架构设计 1. 整体架构 系统采…

html 滚动条滚动过快会留下边框线

滚动条滚动过快时&#xff0c;会留下边框线 但其实大部分时候是这样的&#xff0c;没有多出边框线的 滚动条滚动过快时留下边框线的问题通常与滚动条样式和滚动行为有关。这种问题可能出现在使用了自定义滚动条样式的情况下。 注意&#xff1a;使用方法 6 好使&#xff0c;其它…