【Java数据结构】——第十节(上).直接插入排序、希尔排序

news2024/9/21 14:42:05

 作者简介:大家好,我是未央;

博客首页:未央.303

系列专栏:Java初阶数据结构

每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!

文章目录

一、直接插入排序算法

1.1 算法思路

1.2 算法图解过程

1.3 算法代码

1.4 算法特征总结  

二、希尔排序

2.1 算法思路

2.2 算法图解过

2.3 算法代码程

2.4 算法特征总结  

总结


前言

今天我们将进入到算法的几种常见算法当中,我们首先介绍两种数据结构中最常用的直接插入排序和希尔排序算法;这些经典的排序算法我们必须要熟练的掌握和运用;


一、直接插入排序算法

1.1 算法思路

从数组的第二个元素开始,为把该元素放到前面合适的位置上(在这个过程中可能需要移动前面的元素,给要插入的元素腾出位置

举例说明:

当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移


1.2 算法图解过程


1.3 算法代码

/**
     * 直接插入排序
     * @param array
     */
    public static void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int tmp = array[i];
            int j  = i - 1;
            for (; j >= 0; --j) {
                // [32、56、12、23],i指向12,j一开始指向56,我们就是借助tmp和j的变化,把32、56向后移动一位,把12放到他们前面
                // 这个过程就像把array[i](tmp)插入到数组,放到数组中合适的位置,保证放完后数组是升序(所以才要a[j + 1] = a[j]不断的移动a[j]的位置
                if (tmp < array[j]) {
                    array[j + 1] = array[j]; // 如果a[j]的值大于a[i](tmp),说明a[i]应该放到a[j]前面——a[j]应该向后移动
                }
                else {
                    break; // 此时说明a[j]已经在合适的位置了,不用再次移动了
                }
            }
            array[j + 1] = tmp; //  注意这里不能等于array[i],因为经过上面array[j+1] = array[j]数组的移动,array[i]已经发生了变化
        }
    }

1.4 算法特征总结  

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)(最好情况下-即当数组有序时O(n)
  3.  空间复杂度:O(1),它是一种稳定的排序算法

二、希尔排序

2.1 算法思路

希尔排序法又称缩小增量法。希尔排序法的基本思想是把数据分组,然后再每一组内用直接插入排序对该组的数据进行排序,对每个排完序后再对整个数组进行直接插入排序。

为什么要这样做呢?

上面刚提到过:直接插入排序适合对接近有序的数组进行排序,元素集合越接近有序,直接插入排序的时间效率越高。那么我们就先通过分组排序让这个数组进可能的接近有序,然后不就相当于优化了直接插入排序了吗?

总的来说,希尔排序可以分为两个部分:

  1. 预排序(分组排序,使得数组尽可能趋近有序)
  2. 直接插入排序 

举例说明:

假如有这样一个乱序数组:

解析:
  我们一开始分为3组——即gap(间隔为3),然后对这分别对这三组进行排序;

【9,5,8,5】这4个数就分为一组,【1,7,6】这3个数分为一组,【2,4,3】分为一组。总来说:gap为几,这里就会分割成几组数据。要注意每个组他们元素下标差都是gap

                                                                                                                                                  

接下来就以插入排序的思想对这三组分别进行排序。

既然是分组进行插入排序,那就好办了,像第一组:【9,5,8,5】排序后为【5,5,8,9】,第二组【1,7,6】排序后为【1,6,7】,第三组【2,4,3】排序后为【2,3,4】,如图所示:


2.2 算法图解过程


2.3 算法代码

// 希尔排序——预排序(gap,表示分的组数)
private static void shell(int[] array, int gap) {
    for (int i = gap; i < array.length; i++) {
        int tmp = array[i];
        int j  = i - gap;
        for (; j >= 0; j = j - gap) {
            if (tmp < array[j]) {
                array[j + gap] = array[j]; // 如果a[j]的值大于a[i](tmp),说明a[i]应该放到a[j]前面——a[j]应该向后移动
            }
            else {
                break; // 此时说明a[j]已经在合适的位置了,不用再次移动了
            }
        }
        array[j + gap] = tmp; //  注意这里不能等于array[i],因为经过上面array[j+gap] = array[j]数组的移动,array[i]已经发生了变化
    }
}

我们可以分成把要排序的数组分成不同的组(gap取不同的值)——进行多次预排序,这样我们的数组会更加接近有序;

注意:当gap == 1时,其实就是直接插入排序;

 相应的代码就是:

public class Test3 {
    // 希尔排序——预排序(gap,表示分的组数)
    private static void shell(int[] array, int gap) {
        for (int i = gap; i < array.length; i++) {
            int tmp = array[i];
            int j  = i - gap;
            for (; j >= 0; j = j - gap) {
                if (tmp < array[j]) {
                    array[j + gap] = array[j]; // 如果a[j]的值大于a[i](tmp),说明a[i]应该放到a[j]前面——a[j]应该向后移动
                }
                else {
                    break; // 此时说明a[j]已经在合适的位置了,不用再次移动了
                }
            }
            array[j + gap] = tmp; //  注意这里不能等于array[i],因为经过上面array[j+gap] = array[j]数组的移动,array[i]已经发生了变化
        }
    }
    /**
     * 希尔排序——直接插入排序的优化
     * @param array
     */
    public static void shellSort(int[] array) {
        for (int i =array. length / 3 + 1; i > 1; i = i / 3 + 1) {
            shell(array, i); // 预排序,让我们排序的这个数组接近有序,这样下面的直接插入排序shell(array,1)时间效率才会高
        }
        shell(array, 1); // 这个相当于把数组分成一组,其实就是我们上面写的直接插入排序
    }
    
    public static void main(String[] args) {
        int[] a = {9, 1, 2, 5, 7, 4, 8, 6, 3, 5};
        shellSort(a);
        System.out.println("排序后的数组为:" + Arrays.toString(a));
    }
}

运行结果:


2.4 算法特征总结  

1、希尔排序是对直接插入排序的优化
2、当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
3、稳定性:不稳定
4、时间复杂度:排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算。

总结

本节内容的两个算法就介绍到这里了,下一节内容我们将介绍其他两种算法,让我们继续期待下一节的内容吧!!!!!!!!!!!!!

 

 

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

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

相关文章

iptables 防火墙(一)

目录 一&#xff1a;iptables概述 二&#xff1a;netfilter/iptables关系 三&#xff1a;四表五链 1.规则表和规则链的作用 2. 四表 3.五链 ​4.规则链之间的匹配顺序 &#xff08;1&#xff09;主机型防火墙 &#xff08;2&#xff09;网络型防火墙 5.规则链内的匹配…

考研复试刷题第十四天: 表达式树 【二叉树,表达式运算】

1.概念解释: 表达式树其实就是叶节点装树&#xff0c;其他节点装符号的二叉树。 2.题目部分 这道题一开始没理解它的意思&#xff0c;以后写题一定要理解题意之后再动手。尤其是看清楚注意事项。 我一开始拿到题目&#xff0c;以为会有这种情况就是说一个节点之下会有一遍没…

面了一个测试工程师要求月薪26K,总感觉他背了很多面试题...

最近有朋友去华为面试&#xff0c;面试前后进行了20天左右&#xff0c;包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说&#xff0c;80%的人都会栽在第一轮面试&#xff0c;要不是他面试前做足准备&#xff0c;估计都坚持不完后面几轮面试。 其实&…

OpenLayers多图层切换显示隐藏,支持多个Layer同时显示和隐藏,以百度地图和高德地图为例实现vue的Layer图层管理组件

前言 OpenLayers默认并没有提供图层管理组件,实现起来也很简单,评论区里有同学提到了这个,必须立刻满足,这就着手区实现一个简单又强大的地图图层管理组件。 那么本章就专门讲一下在vue中如何使用ElementUI的下拉框做一个简单的图层管理组件。 话不多说,让我们直接开始吧…

CentOS中vim的使用

vim是我们linux中很经典的一款编译器&#xff0c;所以使用vim是我们在学习过程中必不可少的&#xff0c;我们下面说一下vim的使用和安装 在某些服务器上刚开始不一定时有vim的&#xff0c;或者是vim的版本比较老一点&#xff0c;所以这时我们就可以安装一下vim sudo yum -y i…

最简单的 Java 项目——Hello world(小白快速入门指南)

文章目录 最简单的 Java 项目——Hello world步骤1&#xff1a;新建 Java 项目步骤2&#xff1a;编写最简单的 Hello World 程序步骤3&#xff1a;测试 附录1、.iml文件&#xff08;iml是 intellij idea的工程配置文件&#xff0c;里面是当前project的一些配置信息。&#xff0…

免费开源PCB设计工具--KiCad安装,FreeCAD下载方法

中小企业在使用AD等工具时&#xff0c;会被律师函关照&#xff0c;下面介绍一款跨平台开源PCB设计工具KiCad 。本文仅介绍安装方法。 1. KiCad 简介 KiCad 一个跨平台的开源电子设计自动化套件。 KiCad EDA 是一款用于印刷电路板设计的开源自由软件&#xff0c;最初由法国人…

Shell编程——iptables防火墙

Shell编程——iptables防火墙 一、Linux包过滤防火墙1、Linux防火墙概述2、netfilter3、iptables4、netfilter/iptables关系 二、四表五链1、表链作用2、四表3、五链4、数据包到达防火墙时&#xff0c;规则表之间的优先顺序5、规则链之间的匹配顺序 三、iptables的安装四、ipta…

Swing简述

一、Swing概述 GUI&#xff08;图形用户界面&#xff09;为程序提供图形界面&#xff0c;它最初的设计目的是为程序员构建一个通用的GUI&#xff0c;使其能够在所有的平台上运行&#xff0c;但Java 1.0中基础类AWT&#xff08;抽象窗口工具箱&#xff09;并没有达到这个要求&a…

chatgpt赋能Python-python3_kafka

简介 Kafka是一个分布式的消息队列系统&#xff0c;由LinkedIn开源。它被设计成高性能、高吞吐量的消息传输系统&#xff0c;适用于分布式系统中的实时数据流处理。 Kafka的优势 在使用Kafka之前&#xff0c;我们需要考虑以下问题&#xff1a; 1.数据处理速度是否快速&…

黑客如何从零学起?

一、MYSQL5.7 MySQL是如今使用最多的数据库&#xff0c;是众多企业的首选&#xff0c;在未来几年都将被持续推动发展。 学习MySQL需注重实战操作&#xff0c;循序渐进地了解MySQL中的各项技术&#xff0c;这样才能在实际工作中的关键应用。 想进入网络安全行业&#xff0c; …

机器学习-2 线性回归

线性回归及最大熵模型 算法概述最小二乘法一元线性回归求解方程系数代价函数最小二乘法求解系数 多元线性回归举例 算法应用数据集介绍实现线性回归算法实现线性回归的算法流程最小二乘法的局限性 梯度下降法场景梯度下降算法&#xff08;Gradient Descent&#xff09;算法实例…

Electron,我与你,今天不谈技术谈感情!

目录 前言一、无知二、初见三、再见四、相遇五、行动总结 前言 今天不谈技术&#xff0c;谈谈我和 Electron 的缘分。可能有人觉得&#xff0c;或许有些人认为&#xff0c;和一个框架谈感情这不是疯了吗&#xff1f;但是&#xff0c;我相信每个开发者都会有同样的经历&#xf…

关于蒙特卡罗方法及其在信号处理中的应用

说明 最近想探讨一下毫米波雷达测量准确度及其改善的问题&#xff0c;这个话题下可供讨论的问题有很多&#xff0c;蒙特卡罗方法(或者说基于蒙特卡罗方法对测量准确度以及精度的评估)是其中之一&#xff0c;该方法是一个十分有效的工具&#xff0c;在科研(发paper)上也是不可少…

UE5 C++类如何读取Excel配置表?

UE5 插件开发指南 前言0 如何编写读取数据的结构体?1 如何读取数据?1.0 如何获取数据资产的路径?2 如何调用商店子系统来读取数据?前言 虚幻引擎兼容CSV和JSON格式的数据结构,这里的CSV是Excel表格的保存格式,如下图所示: 打开任意Excel表格,点击文件菜单,然后鼠标悬浮到…

一文2000字从0到1教你搭建有效的测试环境

作为软件测试行业的从业者&#xff0c;搭建测试环境一定是在工作中少不了的任务安排&#xff0c;那么如何有效的搭建测试环境&#xff0c;咱们今天和大家聊一聊。 首先大家要明白测试环境是为了完成软件测试工作所需要的硬件资源&#xff0c;软件资源&#xff0c;网络资源&…

计算机网络实验(ensp)-​实验2:PPP协议及PAP认证

目录 实验报告&#xff1a; 实验操作 1.建立网络拓扑图并开启设备 2.修改路由器名字 1.输入命名&#xff1a;sys 从用户视图切换到系统视图 2.输入命名&#xff1a;sysname 姓名 修改路由器名字 3.重复步骤1和2配置每台路由器 3.抓包 1.点击菜单栏的“数…

(转载)从0开始学matlab(第7天)—运算的优先级与内置函数

1运算的优先级 许多的数学运算写入一个表达式是非常平常的事。例如&#xff0c;考虑初速度为 0 的匀加速运动的位移表达式 distance 0.5 * accel * time ^ 2 这个表达式有二个乘法运算和一个幂运算。在这样的表达式中&#xff0c;知道运算的先后顺序是十分重要的。如果幂运算先…

Redis系统学习篇-02

目录 redis进阶使用 redis作为数据库、缓存的区别 缓存常见问题、面试回答思路 redis的持久化 参考文档(redis.net.cn)&#xff1a;Redis 教程_redis教程 系统学习01篇&#xff0c;总结起来就是&#xff0c;可以把redis想象成一个key/value的hashmap&#xff0c;只不过val…

Linux之路SNAT策略及应用

目录 二、SNAT实验的部署设计 三、具体实验步骤 第一步&#xff1a;做好实验前的虚拟机设置 1&#xff09;网关服务器的设置 ①添加网卡&#xff0c;修改vmnet ②修改ens33为网关服务器的内网网卡 ③修改新加网卡ens36&#xff08;这里添加的网卡是什么就用什么&#xff…