【排序算法】之希尔排序

news2024/11/26 10:32:27

一、算法介绍

希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进。希尔排序又称缩小增量排序,因 DL.Shell 于 1959 年提出而得名。它通过比较相距一定间隔的元素来进行,各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止。希尔排序不是稳定性排序算法。

二、适用场景说明

希尔排序(Shell Sort)适用于以下场景:

  • 中到大型数据集
    希尔排序在处理中等或大型数据集时相比简单的插入排序有显著的性能提升,因为其减少了元素间的比较和移动次数。

  • 数据初始顺序
    如果数据已经部分有序,希尔排序的效率会更高,因为它利用了这一特性来减少排序所需的时间。

  • 时间复杂度要求
    虽然希尔排序的平均和最坏情况时间复杂度不是线性的,但在实践中,对于某些增量序列,它可以在接近线性的时间内完成排序,这对于对时间复杂度有中等要求的场合是有益的。

  • 内存限制
    希尔排序是原地排序算法,不需要额外的存储空间,这在内存有限或者管理内存成本较高的情况下是有优势的。

  • 对稳定性不敏感的应用
    由于希尔排序是非稳定的排序算法,即相等的元素可能会改变相对顺序,所以在那些需要保持相等元素原有顺序的场景下不适用。

  • 简单实现:
    希尔排序的实现相对简单,尽管选择合适的增量序列可以提高性能,但即使使用默认的简单序列,希尔排序也能提供优于直接插入排序的性能。

  • 需要快速响应的初步排序:
    在需要快速得到大致排序结果,但不强求完全排序的场合,希尔排序可以作为一个有效的预处理步骤。

需要注意的是,希尔排序在处理非常大的数据集时,可能不如其他高级排序算法(如快速排序、归并排序或堆排序)表现得好。在现代编程实践中,通常会选择这些具有更好平均和最坏情况时间复杂度保证的算法。然而,希尔排序仍然因其灵活性和在某些特定情况下的高效性而有价值。

三、画图演示

希尔排序目的为了加快速度改进了插入排序,交换不相邻的元素对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。

在此我们选择增量 gap=length/2,缩小增量以 gap = gap/2 的方式,用序列 {n/2,(n/2)/2…1} 来表示。

  1. 初始增量第一趟 gap = length/2 = 4
    在这里插入图片描述
  2. 第二趟,增量缩小为 2
    在这里插入图片描述
  3. 第三趟,增量缩小为 1,得到最终排序结果
    在这里插入图片描述
    当增量gap按照减半的速度递减为1时,排序结束,得到正确的排序结果。

四、java代码

package com.datastructures;

import java.util.Arrays;

/**
 * 希尔排序算法示例
 * @author hulei
 * @date 2024/5/13 14:25
 */


public class ShellSort {
    public static void main(String[] args) {
        Integer[] arr = new Integer[]{7,6,9,3,1,5,2,4};
        System.out.println("排序前:"+Arrays.toString(arr));
        shellSort(arr);
        System.out.println("排序后:"+Arrays.toString(arr));
    }

    /**
     * 实现Shell排序算法的静态方法。
     * <p>
     * 该方法接受一个泛型数组作为输入,该数组的元素必须实现Comparable接口,以便进行排序比较。
     * Shell排序是一种改进的插入排序算法,通过逐渐增加元素间的比较距离来减少排序过程中的交换次数。
     *
     * @param array 要排序的泛型数组,数组元素必须实现Comparable接口。
     * @param <E>   数组元素的类型,该类型需extends Comparable,以确保元素可比较。
     */
       public static <E extends Comparable<? super E>> void shellSort(E[] array) {
        int len = array.length;
        // 通过逐渐减小的间隔对数组进行多趟排序
        for (int gap = len / 2; gap > 0; gap /= 2) {
            // 对每个间隔的元素进行插入排序
            for(int i = gap; i < len; i++){
                // 将当前元素与前面的已排序元素比较并交换位置,直到找到合适的位置
                int j = i-gap;
                while(j>=0){
                    if(array[j].compareTo(array[j + gap]) > 0){
                        swap(array,j+gap,j);
                    }
                    j -= gap;
                }
            }
        }
    }

    /**
     * 交换数组中两个元素的位置。
     *
     * @param array  要进行交换的数组。
     * @param index1 要交换的第一个元素的索引。
     * @param index2 要交换的第二个元素的索引。
     * @param <E>    数组元素的类型。
     */
    private static <E> void swap(E[] array, int index1, int index2) {
        // 临时变量用于存储第一个元素,以便后续交换
        E temp = array[index1];
        array[index1] = array[index2]; // 将第二个元素的值赋给第一个元素
        array[index2] = temp; // 将之前存储的第一个元素的值赋给第二个元素
    }
}

核心方法如下:

    public static <E extends Comparable<? super E>> void shellSort(E[] array) {
        int len = array.length;
        // 通过逐渐减小的间隔对数组进行多趟排序
        for (int gap = len / 2; gap > 0; gap /= 2) {
            // 对每个间隔的元素进行插入排序
            for(int i = gap; i < len; i++){
                // 将当前元素与前面的已排序元素比较并交换位置,直到找到合适的位置
                int j = i-gap;
                while(j>=0){
                    if(array[j].compareTo(array[j + gap]) > 0){
                        swap(array,j+gap,j);
                    }
                    j -= gap;
                }
            }
        }
    }

代码逻辑比较简单了,具体结合上面的图片分析即可
第一层for循环是增量gap除以2逐层递减,初始gap为4,后续是2,1,当gap递减为1时内部循环结束后,停止排序
因为1/2 = 0 ,不满足下一次循环gap>0的条件
中间的for循环是不同的增量间隔,所有元素照间隔当前增量比较
中间一层即使比较增量间隔的两个元素之间比较决定是否并交换位置,大的元素移动到后面,不清楚的话可以在while内部交换后打印出数组内容
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

系统设计 —— 随用户扩展

单服务器设置&#xff1a; 在单服务器设置中&#xff0c;所有内容都运行在一台服务器上。这包括网页应用程序、数据库、缓存等。 1*HQXZgCc5Vh8KooJHwKfzjw.png 图1.1 请求流程 1.最终用户通过域名&#xff08;myurl.com&#xff09;访问网站。请求发送到 DNS&#xff0c;将域名…

字符串函数(一):strcpy(拷贝),strcat(追加),strcmp(比较),及strncpy,strncat,strncmp

字符串函数 一.strcpy&#xff08;字符串拷贝&#xff09;1.函数使用2.模拟实现 二.strcat&#xff08;字符串追加&#xff09;1.函数使用2.模拟实现 三.strcmp&#xff08;字符串比较&#xff09;1.函数使用2.模拟实现 四.strncpy1.函数使用2.模拟实现 五.strncat1.函数使用2.…

[Kubernetes] sealos 部署 K8s v1.25.0 集群

文章目录 1.sealos 介绍2.操作系统基础配置3.安装部署 K8s4.验证 K8s 集群5.部署测试资源 1.sealos 介绍 Sealos 是一个基于 Kubernetes 内核的云操作系统发行版。它采用云原生方式&#xff0c;摒弃传统的云计算架构&#xff0c;转向以 Kubernetes 为云内核的新架构。这使得企…

Python从0到POC编写--函数

数学函数&#xff1a; 1. len len() 函数返回对象&#xff08;字符、列表、元组等&#xff09;长度或项目个数&#xff0c; 例如&#xff1a; str "python" len(str)2. range range() 函数返回的是一个可迭代对象&#xff08;类型是对象&#xff09;&#xff0c;…

安卓短视频一键搬运软件_V1.5.2 高级版

短视频一键搬运app是一款非常实用的视频处理软件&#xff0c;拥有各种各样的视频处理功能&#xff0c;可以帮助用户进行视频的多项处理&#xff0c;首先用户可以在这里为视频去除水印&#xff0c;打开视频文件过后&#xff0c;再把视频里面的水印内容框选出来&#xff0c;这样就…

从“金事通”带给我意想不到的来说--“数据是架构的中心”

背景 上周一个保险的销售人员来找我完成一定的售后流程。其中有一项是请我下载一个叫 金事通的 APP。说实在的我根本没听过。她说这是政治任务。我想不是有你们保险公司的APP了嘛。为什么还要我安装。没办法先安装吧。 经历了注册、人脸识别的步骤后。可以登录了。注册短信发…

Rx(Reactive Extensions)的由来

既然我们已经介绍了响应式编程&#xff0c;现在是时候了解我们的明星了:响应式扩展&#xff0c;通常简称为Rx。微软开发了Reactive扩展库&#xff0c;使其易于处理事件流和数据流。在某种程度上&#xff0c;时变值本身就是一个事件流;每个值更改都是一种类型的事件它会更新依赖…

交通地理信息系统实习教程(二)

这篇文章服务于GIS背景用户以及有志于GIS的朋友 操作源数据位置&#xff1a;【免费】交通地理信息系统实习二源数据资源-CSDN文库 软件安装包位置&#xff1a;【免费】TransCad-交通地理信息系统软件资源-CSDN文库 一、最短路径分析 1.1软件启动说明 这里需要给出一个必要的…

快来参加【顶尖赛事】LIC·2024 语言与智能技术竞赛

语言与智能技术竞赛&#xff08;LIC&#xff09;是由中国中文信息学会&#xff08;CIPS&#xff09;和中国计算机学会&#xff08;CCF&#xff09;联合主办&#xff0c;百度公司、中国中文信息学会评测工作委员会和中国计算机学会自然语言处理专委会承办的中文NLP顶级赛事&…

qt移植到imx6ull运行(qt部署到imx6ull)

这个事情对于小白来说确实不是很友好&#xff0c;会经常出现错误&#xff0c;我弄了两天终于弄好了 我主要参考了https://blog.csdn.net/m0_61738650/article/details/131269561 https://blog.csdn.net/m0_61738650/article/details/131171914这两个教程 我现在来简述一下流程…

AI+新能源充电桩数据集

需要的同学私信联系&#xff0c;推荐关注上面图片右下角的订阅号平台 自取下载。 随着我国新能源汽车市场的蓬勃发展&#xff0c;充电桩的需求量日益增加&#xff0c;充电桩的智能化程度不仅影响充电站运营商的经营效益&#xff0c;也大大影响着用户的充电体验。AI技术可以涵盖…

深入浅出:ConcurrentLinkedQueue源码分析与实战

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

C++青少年简明教程:C++中的常量、变量、表达式和语句

C青少年简明教程&#xff1a;C中的常量、变量、表达式和语句 在C编程中&#xff0c;常量、变量、表达式和语句是基本的编程概念。 常量&#xff08;Constants&#xff09;&#xff1a;在程序中具有固定值的数据称为常量。常量可以是字面值&#xff0c;如整数、浮点数、字符或…

西门子博途WINCC动画之旋转运动

概述 本例将介绍在西门子 TIA Portal HMI 中旋转运动动画的一种实现方法。本例以风机、搅拌器和传送带为例&#xff0c;按下启动按钮开始转动&#xff0c;按下停止按钮停止转动。 第1步&#xff1a; 添加 PLC 设备。​博途TIA/WINCC社区VX群 ​博途TIA/WINCC社区VX群 选择西…

基于SpringBoot的酒店(预约)客房管理系统的设计与实现+毕业论文

系统介绍 酒店客房管理系统为酒店管理者和用户、清洁人员提供一个在线管理酒店客房的系统。在网站的设计中&#xff0c;一共分为了两个模块设计&#xff0c;一个是前台模块&#xff0c;一个是后台模块&#xff0c;前台主要用于提供查看客房信息&#xff0c;酒店资讯&#xff0…

iOS MRC那句话

混编时使用MRC文件需要使用这句话 -fno-objc-arc在下图中显示的位置添加

5月13号作业

使用消息队列实现的2个终端之间的互相聊天 并使用信号控制消息队列的读取方式&#xff1a; 当键盘按ctrlc的时候&#xff0c;切换消息读取方式&#xff0c;一般情况为读取指定编号的消息&#xff0c;按ctrlc之后&#xff0c;指定的编号不读取&#xff0c;读取其他所有编号的消息…

004.可观察对象与观察者

Rx非常适合事件驱动的应用程序。这是有意义的&#xff0c;因为事件(作为)(如前所述)是创建时变值的命令式方法。从历史上看,事件驱动编程主要出现在客户端技术中&#xff0c;因为作为事件实现的用户交互。例如&#xff0c;你可能工作过使用OnMouseMove或OnKeyPressed事件。正因…

commvault学习(7):恢复oracle

在实际生产环境中&#xff0c;oracle的恢复方式大部分是异机恢复。 环境&#xff1a; 备份机&#xff1a;windows server2008&#xff0c;ip&#xff1a;192.168.20.56 恢复目标机&#xff1a;windows server2008&#xff0c;ip&#xff1a;192.168.20.55 CS、MA&#xff1…

acw165. 小猫爬山-DFS剪枝与优化

题目 思路 暴搜顺序&#xff1a;从前往后依次枚举每只小猫&#xff0c;枚举当前这只小猫应该放在哪一辆车上&#xff0c;递归完n层之后&#xff0c;就可以知道所有方案中的最少车辆总数剪枝的情况&#xff1a; 优化搜索顺序&#xff1a;大部分情况下&#xff0c;应该优先搜索分…