七大排序算法(Java实现)——冒泡、快排、插入、希尔、选择、堆排、归并

升序排序为例

交换元素的通用代码:

/*** 交换元素* @param arr* @param idx1* @param idx2*/private void swap(int[] arr, int idx1, int idx2) {int tmp = arr[idx1];arr[idx1] = arr[idx2];arr[idx2] = tmp;}

一、交换排序——冒泡排序

  • 冒泡排序:
  • 相邻两个元素两两比较,若逆序则交换
  • 每一轮会确定一个最大值到它最后的位置上,只需n-1轮排序
  • 优化:如果某一轮排序从头至尾没有发生交换,说明已经有序,结束
/*** 交换排序:稳定,O(n^2)* 1. 冒泡排序:* 相邻两个元素两两比较,若逆序则交换* 每一轮会确定一个最大值到它最后的位置上,只需n-1轮排序* 优化:如果某一轮排序从头至尾没有发生交换,说明已经有序,结束* @param array 待排序列*/public void bubble_Sort(int[] array) {int n = array.length;for(int i = 0; i < n - 1; i++) { // n-1轮排序boolean flag = true;for (int j = 0; j < n - 1 -i; j++) { // 每轮会确定一个最值if(array[j] > array[j + 1]) {  // 逆序则交换swap(array, j, j + 1);flag = false;  // 本轮发生了交换}}if (flag) { // 提前结束break;}}}

二、交换排序——快速排序

  • 快速排序:不稳定,O(nlogn)
  • 随机选出一个元素作为基准pivot,此处选第一个元素array[0]
  • 从序列的两端开始探测,哨兵 i 从前向后找比pivot大的,哨兵 j 从后向前找比pivot小的,然后交换i和j指向的元素;每次都让哨兵j先动
  • 直到哨兵相遇,交换相遇点和pivot
  • 以pivot为基准前后分区,递归左右两个子序列

为什么每次要让哨兵j先动?因为pivot取在左侧

        左侧哨兵i先动,i会找到第一个大于pivot的位置,但哨兵j可能会因为 i小于j 的限制而没有落在小于pivot的位置上,提前结束探测而与i相遇,此时交换,结果是错误的
/*** 交换排序:* 2. 快速排序:不稳定,O(nlogn)* 随机选出一个元素作为基准pivot,此处选第一个元素array[0]* 从序列的两端开始探测,哨兵 i 从前向后找比pivot大的,哨兵 j 从后向前找比pivot小的,然后交换i和j指向的元素;每次都让哨兵j先动* 直到哨兵相遇,交换相遇点和pivot* 以pivot为基准前后分区,递归左右两个子序列** 为什么每次要让哨兵j先动?因为pivot取在左侧* 左侧哨兵i先动,i会找到第一个大于pivot的位置,但哨兵j可能会因为 i小于j 的限制而没有落在小于pivot的位置上,提前结束探测而与i相遇,此时交换,结果是错误的* @param array*/public void quick_Sort(int[] array, int low, int high) {if (low >= high) {return;}int pivot = array[low]; // 基准int i = low; // 哨兵int j = high;while(i < j) {// i < j 确保哨兵在相同处停下(i == j),防止越界while (array[j] >= pivot && i < j) {  //从右往左找比基准值小的数j--;}while (array[i] <= pivot && i < j) {  //从左往右找比基准值大的数i++;}if (i < j) {swap(array, i, j);}}array[low] = array[j]; // 交换基准与哨兵相遇处的元素array[j] = pivot;quick_Sort(array, low, j - 1);quick_Sort(array, j + 1, high);}

三、插入排序——直接插入

  • 直接插入:稳定,O(n^2)
  • 将array[0]视为初始的有序表,从下一个元素开始,逐个插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表
  • 双层循环:外层循环遍历除array[0]外的所有元素,内层循环对当前元有序表进行待插入位置查找(从后向前),并进行移动
/*** 插入排序* 1. 直接插入:稳定,O(n^2)* 将array[0]视为初始的有序表,从下一个元素开始,逐个插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表* 双层循环:外层循环遍历除array[0]外的所有元素,内层循环对当前元有序表进行待插入位置查找(从后向前),并进行移动* @param array*/public void insert_Sort(int[] array) {int n = array.length;for(int i = 1; i < n; i++) {for(int j = i; j >= 1; j--) {if(array[j] < array[j - 1]) { // 从后向前比较,找到插入的位置swap(array, j, j - 1);}else {                      // 比有序表的最后一个元素都大,直接插在末尾break;}}}}

四、插入排序——希尔排序

  • 希尔排序:不稳定,O(n^1.3)
  • 直接插入的改进:分组,组内插入排序
  • 根据增量对序列进行分组,在组内通过直接插入排序,每个组都排好序后,增量减半,再次分组排序,直到增量为1
/*** 插入排序:* 2. 希尔排序:不稳定,O(n^1.3)* 直接插入的改进:分组,组内插入排序* 根据增量对序列进行分组,在组内通过直接插入排序,每个组都排好序后,增量减半,再次分组排序,直到增量为1* @param array*/public void shell_Sort(int[] array) {for(int gap = array.length / 2; gap >=1; gap = gap / 2) {  // gap初始为长度/2, 后逐步/2for (int i = gap; i < array.length; i++) {  // 从每个分组中的第二个元素开始,进行直接插入排序int tmp = array[i];            // 当前待插入的元素int j = i - gap;              // 从后向前比较有序表,j为当前比较到哪个下标了while(j >= 0 && array[j] > tmp) {array[j + gap] = array[j];  // 逆序,a[j] 后移j -= gap;}array[j + gap] = tmp; // while结束,j是不满足的下标,需+gap,将tmp插在此处}}}

五、选择排序——简单选择

  • 简单选择排序:不稳定, O(n^2)
  • 每轮在待排序列中找min,将其添加至有序表的末尾
/*** 选择排序:* 1. 简单选择排序:不稳定, O(n^2)* 每轮在待排序列中找min,将其添加至有序表的末尾* @param array*/public void select_Sort(int[] array) {int n = array.length;for(int i = 0; i < n - 1; i++) { // 当前待插入位置,有序表的最末maxint min_index = i;for(int j = i + 1; j < n; j++) {  // 找min的下标if (array[min_index] > array[j]) {min_index = j;}}if (min_index != i) {swap(array, i, min_index);}}}

六、选择排序——堆排序

  • 堆排序:升序使用大根堆(父节点大于左右孩子的完全二叉树),不稳定,O(nlogn)
  • 将待排序列构造小根堆:建堆O(n),然后调整成一个小根堆
  • 将堆顶与最后一个元素交换,再从堆顶开始调整,将原堆顶脱离大根堆,即序列的max,逐步得到当前堆的堆顶max
/*** 选择排序:* 2. 堆排序:升序使用大根堆(父节点大于左右孩子的完全二叉树),不稳定,O(nlogn)* 将待排序列构造小根堆:建堆O(n),然后调整成一个小根堆* 将堆顶与最后一个元素交换,再从堆顶开始调整,将原堆顶脱离大根堆,即序列的max,逐步得到当前堆的堆顶max** @param array*/public void heap_Sort(int[] array) {int n = array.length;// 建堆:向下调整建堆O(n)和向上调整建堆O(nlogn)// 子节点i的父节点下标:(i- 1)/2,从最后一个节点父节点开始for (int i = (n - 1 - 1) / 2; i >= 0; i--) { // 从后向前,可以保证子树已经是大根堆,这样才能使用向下调整heapify(array, n, i);}// 堆顶与最末交换,调整for (int i = n - 1; i >= 0; i--) {swap(array, n - 1, 0);  // 交换n--;                     // 使交换至末尾的max脱离堆heapify(array, n, 0); // 调整堆}}/*** 调整、维护堆(大根堆)* @param array* @param n  数组长度* @param i 待维护节点下标*/public void heapify(int[] array, int n ,int i) {int lson = 2 * i + 1;int rson = 2 * i + 2;int max_index = i; // 假设当前节点是最小值// 找到最小节点的下标if(lson < n && array[max_index] < array[lson]) {  // min_index > 左,调整max_index = lson;}if (rson < n && array[max_index] < array[rson]) {  // min_index > 右,调整max_index = rson;}if (max_index != i) {  // 父节点不是min,与min交换调整swap(array, max_index, i);heapify(array, n, max_index);  // 调整后可能导致子树不符合规定,递归调整}}

七、归并排序

  • 归并排序:稳定,O(nlogn)
  • 分治思想
  • 将序列从中间一分为二,递归拆分,直到包含单一元素,将其视为有序表
  • 从左右数组中选择小的元素放入到临时空间,后移下标,直到某一数组的下标达到尾部,将另一序列剩下的所有元素依次放入临时空间,将临时空间的数据依次放入原数据数组
/*** 归并排序:稳定,O{nlogn)* 分治思想:将序列从中间一分为二,递归拆分,直到包含单一元素,将其视为有序表* 从左右数组中选择小的元素放入到临时空间,后移下标,直到某一数组的下标达到尾部,将另一序列剩下的所有元素依次放入临时空间,将临时空间的数据依次放入原数据数组* @param array*/public void merge_Sort(int[] array, int left, int right, int[] tmp_array) {if (left >= right) {  // 递归出口:每组只有一个元素left == rightreturn;}int mid = (right + left) / 2;merge_Sort(array, left, mid, tmp_array);merge_Sort(array, mid+1, right, tmp_array);merge(array, left, mid, right, tmp_array);  // 合并}public void merge(int[] array, int left, int mid, int right, int[] tmp_array) {int i = left;  // i j 分别指向两个数组的第一个元素int j = mid + 1;
//        int[] tmp_array = array.clone();  //克隆,遍历tmp_array,改变array——>占用空间,传入一个克隆,但注意每次合并完后更新tmp_array与array保持一致int tmp_index = left;while(i <= mid && j <= right) {if(tmp_array[i] < tmp_array[j]) {array[tmp_index] = tmp_array[i];i++;tmp_index++;}else {array[tmp_index] = tmp_array[j];j++;tmp_index++;}}// 其中一个序列结束了,但另一个还有元素,直接加入(肯定是有序的)while (i <= mid) {array[tmp_index] = tmp_array[i];i++;tmp_index++;}while (j <= right) {array[tmp_index] = tmp_array[j];j++;tmp_index++;}// 一次合并后临时数组要和nums同步for(i = left; i <= right; i++)tmp_array[i] = array[i];}

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

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

相关文章

sql连续登录

1、sql建表语句 DROP TABLE IF EXISTS app_login_record; CREATE TABLE app_login_record (user_id int(0) NULL DEFAULT NULL,enter_time datetime(0) NULL DEFAULT NULL,leave_time datetime(0) NULL DEFAULT NULL );INSERT INTO app_login_record VALUES (789012, 2023-05-…

自动式挂机游戏,全新玩法,实现睡后收入,日产8000

项目简介&#xff1a; 最近&#xff0c;许多朋友询问关于支付宝钱包无人直播游戏的玩法。我已经研究了一个月&#xff0c;今天终于迎来了好消息&#xff01;市场上的价格在1980到5980元不等&#xff0c;但今天我花了1980元买下了这个游戏的玩法。老实说&#xff0c;原本这个玩法…

全志ARM-超声波测距

超声波测距模块是用来测量距离的一种产品&#xff0c;通过发送和收超声波&#xff0c;利用时间差和声音传播速度&#xff0c; 计算出模块到前方障碍物的距离 1.测距原理&#xff1a; 给Trig端口至少10us的高电平发送声波&#xff0c;Echo信号&#xff0c;由低电平跳转到高电平…

Open-Sora 升级技术报告解读

最新功能概览 开源地址&#xff1a;https://github.com/hpcaitech/Open-Sora 技术报告&#xff1a;Open-Sora/docs/report_02.md at main hpcaitech/Open-Sora GitHub技术报告&#xff1a; 支持长视频生成&#xff1b;视频生成分辨率最高可达 720p&#xff1b;单模型支持任…

Semtech ClearEdge™ technology的理解

EML&#xff08;External Cavity Laser&#xff09;外腔激光 DML&#xff08;Distributed Feedback Laser&#xff09;分布式反馈激光 EML激光器&#xff0c;即光电调制激光器&#xff0c;其工作原理基于光电效应。通过在半导体材料上施加电压来调制激光的振幅和相位&#xff0…

vue如何发送请求给后端(包括前后端跨域)

目录 有哪些方法可以发送请求要请求先解决跨域问题代理服务器后端解决跨域问题 axios发送请求vue-resource发送请求 有哪些方法可以发送请求 以前可能了解过&#xff1a; xhr 即&#xff1a;new XMLHttpRequest()jQuery 即&#xff1a;$.get $.postaxios fetch 在vue中特有的…

数据安全能力成熟度模型(DSMM)

DSMM的架构由以下三个维度构成&#xff1a; a) 安全能力维度 安全能力维度明确了组织在数据安全领域应具备的能力&#xff0c;包括组织建设、制度流程、技术工具和人员能力。 b&#xff09;能力成熟度等级维度 数据安全能力成熟度等级划分为五级&#xff0c;具体包括&…

笔试强训未见过题(个人向)

1.游游的水果大礼包 题目 解析 我们设卖出价值为c&#xff0c;卖出x个一号礼包&#xff0c;y个二号礼包。则caxby&#xff0c;那么就可以一一枚举&#xff0c;x的最大值为min&#xff08;a/2&#xff0c;b&#xff09;&#xff0c;则y就为min&#xff08;a-2*min&#xff0c;…

js的一些内置函数

JavaScript 提供了许多内置函数&#xff0c;这些函数可以直接在代码中调用&#xff0c;无需自定义。以下是一些常见的 JavaScript 内置函数&#xff1a; Math 对象函数: Math.abs(x): 返回 x 的绝对值。Math.ceil(x): 对 x 进行上舍入。Math.floor(x): 对 x 进行下舍入。Math.r…

《C++的类型转换》

目录 一、c语言中的类型转换 1、隐式类型转化&#xff1a; 2、强制类型转化&#xff1a; 3、缺点 二、c新的类型转换 1、内置类型转为自定义类型 3、自定义类型转换为内置类型 三、C的规范的强制类型转换 1、C新增四种规范的类型转换的原因 2、static_cast 3、reint…

PotatoPie 4.0 实验教程(29) —— FPGA实现摄像头图像均值滤波处理

图像的均值滤波简介 图像均值滤波处理是一种常见的图像处理技术&#xff0c;用于降低图像中噪声的影响并平滑图像。该方法通过在图像中滑动一个固定大小的窗口&#xff08;通常是一个正方形或矩形&#xff09;&#xff0c;将窗口中所有像素的值取平均来计算窗口中心像素的新值…

【Android】SharedPreferences阻塞问题深度分析

前言 Android中SharedPreferences已经广为诟病&#xff0c;它虽然是Android SDK中自带的数据存储API&#xff0c;但是因为存在设计上的缺陷&#xff0c;在处理大量数据时很容易导致UI线程阻塞或者ANR&#xff0c;Android官方最终在Jetpack库中提供了DataStore解决方案&#xf…

AI做画的算法原理

AI做画的算法主要是基于神经网络&#xff0c;特别是一种称为生成对抗网络&#xff08;GAN&#xff09;的深度学习模型。 生成对抗网络由两部分组成&#xff1a;生成器和判别器。 生成器从一个随机噪声向量开始&#xff0c;然后经过一系列卷积神经网络&#xff0c;生成一个图片…

数据结构——插入排序

基本思想&#xff1a; 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a;把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 。 实际中我们玩扑克牌时&…

1146. 快照数组

java版本 class SnapshotArray {int id 0;List<int[]>[] snapshots;public SnapshotArray(int length) {snapshots new List[length];for (int i 0; i < length; i) {snapshots[i] new ArrayList<int[]>();}}public void set(int index, int val) {snapsho…

XYCTF-部分web总结

这个月在XYCTF中写了部分web题&#xff0c;题中学到在此记录一下 ezhttp 打开就是一个简单的登录页面 f12说藏在一个地方&#xff0c;先想到的就是robots.txt 访问直接给账号密码 username: XYCTF password: JOILha!wuigqi123$登录后: 明显考源跳转&#xff0c;修改referer值…

如何查看 UUID 是那个版本

UUID 是有多个版本的&#xff0c;如何查看 UUID 是那个版本&#xff0c;可以用 UUID 对象中的 version() 方法。 创建 UUID 对象&#xff1a; UID originalUUID UUID.fromString("cc5f93f7-8cf1-4a51-83c6-e740313a0c6c"); uuid.version();上面方法显示 UUID 的版本…

通用模型Medprompt如何在医学领域超越专家系统

在AI的发展历程中&#xff0c;一直存在着两种理念的较量&#xff1a;一种是追求普适性的通用AI模型&#xff0c;另一种是针对特定领域深度优化的专业AI系统。最近&#xff0c;微软的研究团队在这一辩论中投下了一枚重磅炸弹——他们开发的Medprompt策略&#xff0c;使得通用AI模…

Gin框架入门(四)—中间件

文档 官方文档&#xff1a;https://godoc.org/github.com/gin-gonic/gin 官方地址&#xff1a;https://github.com/gin-gonic/gin 中间件&#xff1a;https://gin-gonic.com/zh-cn/docs/examples/using-middleware 无中间件 func main() {//创建一个无中间件路由r : gin.New…

Flask教程:flask框架基础入门,路由、模板、装饰器

文章目录 一、 简介二、 概要 一、 简介 Flask是一个非常小的Python Web框架&#xff0c;被称为微型框架&#xff1b;只提供了一个稳健的核心&#xff0c;其他功能全部是通过扩展实现的&#xff1b;意思就是我们可以根据项目的需要量身定制&#xff0c;也意味着我们需要学习各…