5.冒泡+选择+插入+希尔

一、排序算法

排序基础
1.排序算法的稳定性在这里插入图片描述
2.何为原地排序算法
在这里插入图片描述

1.冒泡排序

在这里插入图片描述
从下面第一个元素开始往上冒泡,一轮冒泡下来,最大的元素就去了最上面了
在这里插入图片描述
步骤:无序数组
在这里插入图片描述
每次冒泡都可以将最大的元素放到最右边去
第一轮比较了5次:
在这里插入图片描述
第二轮比较了4次:
在这里插入图片描述
第三轮比较了3次:
在这里插入图片描述
。。。
第四轮比较了2次
。。。
在这里插入图片描述
有6个元素比较了6次,第一次比较了5次,第二次4次。。。
code:
两次遍历,第一次控制冒泡的轮数,第二次控制每次比较次数

public class BubbleSorter {public void sort(int[] data){if(data == null || data.length <=1) return;for (int round = 1; round <= data.length; round++) { //控制冒泡的轮数int compareTimes = data.length - round;for (int i = 0; i < compareTimes; i++) {   //控制每轮比较次数if(data[i]>data[i+1]){int tmp = data[i];data[i] = data[i+1];data[i+1] = tmp;}}}}public static void main(String[] args) {int[] data = new int[]{12,23,36,9,24,42};new BubbleSorter().sort(data);System.out.println(Arrays.toString(data));}
}

特点

  • 时间复杂度分析:
    时间复杂度:O(n²)
    在这里插入图片描述
    在这里插入图片描述
  • 空间复杂度为O(1),原地排序算法
  • 冒泡排序是稳定的排序算法
    在这里插入图片描述
    只有大于才进行交换,两个36的位置不会改变
    优化:减少元素交换次数
    在这里插入图片描述
    在这里插入图片描述
    在第二轮中已经是有序的了,就不需要再进行第三轮、第四轮交换了

代码实现

public class BubbleSorter {public void sort(int[] data){if(data == null || data.length <=1) return;for (int round = 1; round <= data.length; round++) { //控制冒泡的轮数boolean hasSwap = false;int compareTimes = data.length - round;for (int i = 0; i < compareTimes; i++) {   //控制每轮比较次数if(data[i]>data[i+1]){int tmp = data[i];data[i] = data[i+1];data[i+1] = tmp;hasSwap = true;}}//如果没有发生交换就可以退出了if(!hasSwap){break;}}}public static void main(String[] args) {int[] data = new int[]{12,23,36,9,24,42};new BubbleSorter().sort(data);System.out.println(Arrays.toString(data));}
}

2. 选择排序

重在选择,每次选择出来一个最小的元素和前面的元素进行交换
选择排序的步骤:
1.找到数组中最小的数组元素
2.将这个最小的数组元素和数组第一个元素进行交换
3.在剩下元素中找到最小的数组元素和数组第二个元素进行交换
。。。
假设第一个元素是最小值,在剩下元素里面找最小值,还需要一个指针 j 来遍历数组找最小值,和 i 进行比较
在这里插入图片描述
遍历到12的时候,12比第一个元素值小,可能是最小值,将其索引放到minNumIndex中
在这里插入图片描述
第一轮遍历完成后就可以找到数组中最小的元素值的索引,存放在minNumIndex中,将这个索引指向的元素和指针i 指向的元素进行交换
第二轮:
在这里插入图片描述
在这里插入图片描述
第三轮:
在这里插入图片描述
在这里插入图片描述
第三轮,找到最小元素值的索引为4,将其和 i 指针指向元素进行交换
。。。
在这里插入图片描述
数组有多少个元素就需要进行多少轮的排序
时间复杂度:O(n²)
在这里插入图片描述
code:
将交换元素的方法抽取为父类

public class Sorter {public void swap(int[] nums,int i,int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}
}

代码实现

public class SelectionSort extends Sorter{public void sort(int[] data){if(data == null || data.length<=1) return;for (int i = 0; i < data.length; i++) { //控制选择排序的轮数//找到[i,n)中的最小元素所在的索引  minNumIndex用来存放最小值的索引int minNumIndex = i;//j从i+1开始遍历数组,找到最小元素值for (int j = i+1; j < data.length; j++) {if(data[j]<data[minNumIndex]){minNumIndex = j;}}//将data[i]和最小元素进行交换swap(data,i,minNumIndex);}}public static void main(String[] args) {int[] data = new int[]{12,23,36,9,24,42};new SelectionSort().sort(data);System.out.println(Arrays.toString(data));}
}

特点

  • 空间复杂度:O(1),原地排序算法 时间复杂度:O(n²)
  • 选择排序是不稳定的排序算法
    在这里插入图片描述

3. 插入排序

将每一个元素插入到已经有序的数组的位置
在这里插入图片描述
核心思想:取未排序区间的元素在已排序区间中找到合适的插入位置将其插入,并保证已排序区间的数据一直有序,重复这个过程直到未排序区间没有元素为止
一般是假设第一个元素为已排序元素
在这里插入图片描述
插入排序的步骤:有n个元素就进行n轮
第一轮:取第一个元素34,这个元素已经有序
在这里插入图片描述
第二轮:
在这里插入图片描述
从第二个元素开始,对比 j 指向元素和 j-1 元素,如果比 j-1 元素值要小,则进行交换
在这里插入图片描述
在这里插入图片描述
第三轮:从第三个元素开始,比前一个元素,位置正确不用动
在这里插入图片描述
第四轮:从第四个元素开始,比前一个元素小,要向前移动
在这里插入图片描述
在这里插入图片描述
进行交换,注意此时,j-1 和 j 需要继续向前移动
第五轮:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第六轮:
在这里插入图片描述

拿到未排序区间的元素,一直往前找,找到合适的位置将这个元素插入进去,一直到未排序区间为空,就表示这个数组排序完成了
时间复杂度:
遍历一遍数组,时间复杂度为O(n)
每轮遍历需要将一个元素插入到有序数组的正确位置这个插入过程的最坏时间复杂度为O(n)
根据乘法法则:O(n²)
code:

代码实现(优化前)

public class InsertionSorter extends Sorter{public void sort(int[] data){if(data==null||data.length<=1)return;for (int i = 1; i < data.length; i++) { //控制插入排序的轮数,第一个元素已经默认有序,可以存第二个开始for (int j = i; j > 0 ; j--) {  //j从i开始向前移动,和j-1进行判断,j-1不能小于0,j-1也不能等于0,不然就变成data[-1]了if(data[j] < data[j-1]){swap(data,j,j-1);}else{break;}}}}public static void main(String[] args) {int[] data = new int[]{12,23,36,9,24,42};new InsertionSorter().sort(data);System.out.println(Arrays.toString(data));}
}

特点

  • 空间复杂度是O(1),时间复杂度为O(n²),原地排序算法
  • 插入排序是稳定的排序算法,可以选择不去进行交换,只有小于的时候才去交换
    在这里插入图片描述

代码实现(优化后)

插入排序的优化:
不使用元素交换,使用赋值代替元素交换,减少元素访问次数
可以将有序数组中较大的元素总是向右移动,然后将元素插入到正确的位置

//优化
public void sort1(int[] data){if(data==null||data.length<=1)return;for (int i = 1; i < data.length; i++) { //控制插入排序的轮数,第一个元素已经默认有序,可以存第二个开始int tmp = data[i];int j;for (j = i; j > 0 ; j--) {  //j从i开始向前移动,和j-1进行判断,j-1不能小于0,j-1也不能等于0,不然就变成data[-1]了if(tmp < data[j-1]){//将较大的元素向后移动data[j] = data[j-1];}else{break;}}//找到i 对应的元素需要插入的位置data[j] = tmp;}
}

冒泡、选择、插入排序性能对比

时间复杂度都是O(n²)
通过比较交换次数来比较性能

package com.douma.line.algo.sort;import java.util.Random;/*** 对比冒泡、选择、插入排序性能*/
public class SortCompare {private static Random random = new Random();private static int[] getData(int n){int[] data = new int[n];for (int i = 0; i < n; i++) {data[i] = random.nextInt();}return data;}private static long time(String sortType,int[] data){long start = System.currentTimeMillis();if(sortType.equals("bubble"))new BubbleSorter().sort(data);else if(sortType.equals("selection"))new SelectionSort().sort(data);else if(sortType.equals("insertion"))new InsertionSorter().sort(data);return System.currentTimeMillis() - start;}private static long manyTimeSort(String sortType,int n,int k){long totalTime = 0;for (int i = 0; i < k; i++) {totalTime += time(sortType,getData(n));}return totalTime;}public static void main(String[] args) {double t1 = manyTimeSort("bubble",1000,100);double t2 = manyTimeSort("selection",1000,100);double t3 = manyTimeSort("insertion",1000,100);System.out.println(t1 / t2);    //t1 > t2System.out.println(t2 / t3);    //t2 > t3//结论:插入排序性能最好(稳定),其次是选择排序(不稳定),最后是冒泡排序(稳定)}
}

推荐使用插入排序,性能最好,是稳定的
插入排序有两种实现方式,一种是基于交换实现的;另一种是基于赋值实现的;赋值的效率要比交换效率要高

4. 希尔排序

什么是希尔排序?
是对插入排序的优化
如果有一个大规模乱序数组插入排序很慢,因为它只会交换相邻的两个元素
在这里插入图片描述
这个大规模数组在进行若干次插入排序后,前面已经有序了,最后一个是最小的元素,这个时候需要将最小元素一步步的向前比较移动,
在这里插入图片描述
这个过程会非常慢
希尔排序就可以解决大规模数组插入排序慢的问题

希尔排序的思想:
先使数组中任间隔为h(4)的元素有序,然后对全局(也就是h=1)进行排序
希尔排序递增序列计算公式
间隔h的取值逻辑
在这里插入图片描述
在这里插入图片描述
最常用的是:
在这里插入图片描述
递增序列的取值:
在这里插入图片描述
使用公式计算得出h取值,k取1,2,3,4,5带入公式计算出h取值,h应该小于N/3

public class ShellSorter {public void sort(int[] data){if(data == null || data.length <=1)return;//1.计算递增序列int n = data.length;ArrayList<Integer> list = new ArrayList<>();int k = 1;int h;do{h = (int)(Math.pow(3,k)-1)/2;if(h > n/3)break;list.add(h);    // 1,4,13,40,121....k++;}while (h <= n/3);}
}

倒序遍历递增序列

//2.希尔排序
for (k = list.size()-1; k >=0 ; k--) {  //倒序遍历递增序列h = list.get(k);// 将数组变为 h 有序}

希尔排序详细步骤
希尔排序过程 h = 4,经过此次排序,间隔为4的元素就局部有序了
全局排序 h =1

代码实现

public class ShellSorter extends Sorter{public void sort(int[] data){if(data == null || data.length <=1)return;//1.计算递增序列int n = data.length;ArrayList<Integer> list = new ArrayList<>();int k = 1;int h;do{h = (int)(Math.pow(3,k)-1)/2;if(h > n/3)break;list.add(h);    // 1,4,13,40,121....k++;}while (h <= n/3);//2.希尔排序for (k = list.size()-1; k >=0 ; k--) {  //倒序遍历递增序列h = list.get(k);// 将数组变为 h 有序for (int i = h; i < n; i++) { //倒序遍历for (int j = i; j >= h ; j=j-h) {  if(data[j] < data[j-h]){swap(data,j,j-h);}else{break;}}}}}public static void main(String[] args) {int[] data = new int[]{12,23,36,9,24,42};new ShellSorter().sort(data);System.out.println(Arrays.toString(data));}
}

希尔排序对比插入排序性能
性能要比插入排序好,具体要看递增序列h的取值,根据公式获取

特点

希尔排序的特点

  • 空间复杂度:O(1),原地排序算法
  • 希尔排序是不稳定的排序算法
    在这里插入图片描述

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

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

相关文章

开箱机特点与操作因素:深入剖析影响效率的关键因素

在现代化物流和生产流程中&#xff0c;开箱机作为一种自动化、高效率的设备&#xff0c;正逐渐成为企业提升工作效率、降低人工成本的得力助手。然而&#xff0c;要想充分发挥开箱机的性能优势&#xff0c;就必须深入了解其特点与操作因素&#xff0c;并准确把握影响效率的关键…

Navicat for MySQL 11软件下载附加详细安装教程

根据使用者情况表明Navicat Premium 能使你快速地在各种数据库系统间传输数据&#xff0c;或传输到一份指定 SQL 格式和编码的纯文本文件&#xff0c;计划不同数据库的批处理作业并在指定的时间运行&#xff0c;其他功能包括导入向导、导出向导、查询创建工具、报表创建工具、数…

Idea | Idea提交.properties文件乱码问题

这里 Transparent natice-to-ascii conversion 自动转换ASCII码 千万别勾选

第 5 章:面向生产的 Spring Boot

在 4.1.2 节中&#xff0c;我们介绍了 Spring Boot 的四大核心组成部分&#xff0c;第 4 章主要介绍了其中的起步依赖与自动配置&#xff0c;本章将重点介绍 Spring Boot Actuator&#xff0c;包括如何通过 Actuator 提供的各种端点&#xff08;endpoint&#xff09;了解系统的…

优雅迷人的小程序 UI 风格

优雅迷人的小程序 UI 风格

每日一题——Python实现PAT甲级1116 Come on! Let‘s C(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码点评 时间复杂度分析 空间复杂度分析 总结 我要更强 优化思路 优化…

全球首个光量子计算机生产线落地!量子计算机要量产了

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 文丨娴睿/慕一 排版丨沛贤 深度好文&#xff1a;1000字丨5分钟阅 摘要&#xff1a;欧洲量子计算服务提供商Quandela以其创新的光量子比特生产技术&#xff0c;致力于推动量子计算的工业规模化…

三角剖分技术在AI绘画中的艺术与创新

引言&#xff1a; 随着人工智能技术的不断进步&#xff0c;AI绘画作为一种新兴的艺术创作方式逐渐进入人们的视野。它不仅改变了传统艺术创作的模式&#xff0c;还为艺术家和设计师提供了全新的工具。在AI绘画中&#xff0c;三角剖分技术扮演着至关重要的角色&#xff0c;它不仅…

ABeam News | ABeam德硕受邀参访建王设计,细化双方ESG合作可能点

0523 ABeam News 左起&#xff1a;ABeam大中华区董事长兼总经理中野洋辅、建王设计北京办公室总监田禾、建王设计北京办公室总经理王丽、ABeam中国ESG与可持续发展负责人杨丽楠、ABeam上海办公室王培培 建王 随着ESG&#xff08;环境、社会和治理&#xff09;理念近年来的持续…

Springboot的小型超市商品展销系统-计算机毕业设计源码01635

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&#xff0c;应用软件的工作…

Lua解释器裁剪

本文目录 1、引言2、文件功能3、选择需要初始化的库4、结论 文章对应视频教程&#xff1a; 已更新。见下方 点击图片或链接访问我的B站主页~~~ Lua解释器裁剪&#xff0c;很简单~ 1、引言 在嵌入式中使用lua解释器&#xff0c;很多时候会面临资源紧张的情况。 同时&#xff0c…

以 ZGC 为例,谈一谈 JVM 是如何实现 Reference 语义的

本文基于 OpenJDK17 进行讨论 1. Reference 相关概念及其应用场景总览 Reference&#xff08;引用&#xff09;是 JVM 中非常核心且重要的一个概念&#xff0c;垃圾回收器判断一个对象存活与否都是围绕着这个 Reference 来的&#xff0c;JVM 将 Reference 又细分为几种具体的引…

记录汇川:计算机-ST

某小学校内&#xff0c;数学教学组&#xff0c;为了能给新进学生更好的体验到电子计算器高速的计算能力&#xff0c;打算打造一个计算实操台&#xff0c;能够兼容任意数字的加、减、乘、除的功能全自动计算器实操台项目由可编程逻辑控制器与人机界面组成。 1、拥有加、减、乘、…

Tkinter的完美伴侣:加强版GUI库揭秘(界面升级不止步:如何用一个库强化Tkinter)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒🚀 安装🔖 创建第一个应用💡 主要特性🔓 主题切换📢 示例项目⚓️ 相关链接 ⚓️📖 介绍 📖 Tkinter作为Python标准库中最常用的GUI工具包,其简单易用的特性深受开发者喜爱。然而,Tkinter在界面美…

共话大模型技术进展与挑战,CCF大模型论坛北京会议圆满落幕!

2024 年 6 月 6 日中国计算机学会大模型论坛&#xff08;CCF FoLM&#xff09;主题会议在北京顺利举办。本次会议主题为“大模型技术进展与挑战”&#xff0c;各位专家围绕大模型技术的前沿动态、发展趋势及技术挑战等议题展开深入探讨&#xff0c;为广大从业者、研究者提供了一…

C#开源项目推荐:Watt Toolkit跨平台游戏工具箱支持github网络加速

Watt Toolkit是一个开源跨平台的多功能游戏工具箱&#xff0c;主要专注于增强玩家在Steam平台上的游戏体验及国外网站平台加速。 主要功能 兼容性 用户数据 团队背景 github加速功能 使用方法&#xff1a;用户只需在Watt Toolkit中启用网络加速功能&#xff0c;并选择对Gi…

LogicFlow 学习笔记——3. LogicFlow 基础 节点 Node

节点 Node LogicFlow 内置了一些基础节点&#xff0c;开发者在实际应用场景中&#xff0c;可以基于这些基础节点&#xff0c;定义符合自己业务逻辑的节点。 认识基础节点 LogicFlow是基于svg做的流程图编辑框架&#xff0c;所以我们的节点和连线都是svg基本形状&#xff0c;…

【DPDK学习路径】二、DPDK简介

DPDK(Data Plane Development Kit)是一个框架&#xff0c;用于快速报文处理。 在linux内核提供的报文处理模型中&#xff0c;接收报文的处理路径为&#xff1a;首先由网卡硬件接收&#xff0c;产生硬中断&#xff0c;触发网卡驱动程序注册的中断函数处理&#xff0c;之后产生软…

后继者00

题目链接 后继者 题目描述 注意点 题目中的树是二叉搜索树节点p在二叉搜索树中一定存在 解答思路 本题关键是找到值大于节点p的值的第一个节点&#xff0c;因为本题中的树是二叉搜索树&#xff0c;所以左子树的值始终小于根节点&#xff0c;右子树的值始终大于根节点访问到…

鸿蒙开发:通过startAbilityByType拉起垂类应用

通过startAbilityByType拉起垂类应用 使用场景 开发者可通过特定的业务类型如导航、金融等&#xff0c;调用startAbilityByType接口拉起对应的垂域面板&#xff0c;该面板将展示目标方接入的垂域应用&#xff0c;由用户选择打开指定应用以实现相应的垂类意图。垂域面板为调用…