JAVA ---- 经典排序算法

news2024/11/24 19:13:47

目录

一. 插入排序

1.  直接插入排序 

 代码演示

2.希尔排序( 缩小增量排序 )

二. 选择排序 

1.直接选择排序 

代码: 

2. 堆排序 

代码 

三.  交换排序 

1. 冒泡排序 

代码 

2.  快速排序 

代码(有注释): 


动图来自网路 

一. 插入排序

1.  直接插入排序
 

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。 

由上图可清晰的看到,如何直接插入,从第二个(下标为 1 )开始 ,向前比较,以此类推

 代码演示

/**
     * 插入排序
     * @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 = i - 1; j >= 0 ; j--) {
                if(array[j] > tmp){
                    //就是让大的往后挪
                    array[j + 1] = array[j];
                }else {
                    break;
                }
            }
            array[j + 1] = tmp;
        }
    }

直接插入总结:
1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:稳定

2.希尔排序( 缩小增量排序 )

先选定一个整数,把待排序文件中所有记录分成多个组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达gap=1时,所有记录在统一组内排好序 

 

/**
     * 希尔排序
     * @param array
     */
    public static void shellSort(int[] array){
        int gap = array.length;//增量
        while(gap > 1){
            gap = gap/2;
            shell(array, 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-=gap){
                if(array[j] > tmp){
                    array[j + gap] = array[j];
                }else {
                    break;
                }
            }
            array[j + gap] = tmp;
        }
    }

希尔排序总结:
1. 希尔排序是对直接插入排序的优化。
2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。
3. 希尔排序的时间复杂度不好计算,(
O(n^1.3) ~O(n^1.5))因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定。 

4.不稳定

二. 选择排序
 

1.直接选择排序
 

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

   

代码: 

/**
     * 选择排序
     * @param array
     */
    public static void selectSort(int[] array) {
        int i = 0;
        for(i = 0; i < array.length; i++){
            int minIndex = i;
            int j = i + 1;
           for(j = i + 1; j < array.length; j++){
               if(array[minIndex] > array[j]){
                    minIndex = j;
               }
           }
           int tmp = array[i];
           array[i] = array[minIndex];
           array[minIndex] = tmp;
        }
    }

直接选择排序总结:
1. 直接选择排序,效率不是很好。实际中很少使用
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:不稳定 

2. 堆排序 

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。 

简单来说,把数组变成大根堆,之后让第一个和最后一个交换,然后再把换后的变成大根堆,这样最大的就都再后面了 

代码 

/**
     * 堆排序
     * 把数组变成大根堆,之后让第一个和最后一个交换,然后再把换后的变成大根堆,这样最大的就都再后面了
     * @param array
     */
    public static void heapSort(int[] array){
       int end = array.length - 1;
        for (int parent = (array.length - 1 - 1) / 2; parent >= 0; parent--) {
            //和孩子节点换
            shiftDown(parent, array.length, array);
        }
       while (end > 0){
           swap(array, 0, end);
           shiftDown(0, end, array);
           end--;
       }
    }
    private static void swap(int[] array, int begin, int end){
       int tmp = array[begin];
       array[begin] = array[end];
       array[end] = tmp;
    }
    private static void shiftDown(int parent,int usedSize,int[] array) {
        int child = (2*parent) + 1;//左孩子节点
        //不越界
        while (child < usedSize){
            //先比较一下孩子们的大小,找到当中最大的
            if(child + 1 < usedSize && array[child] < array[child + 1]){
                child = child + 1;
            }
            //然后再和parent比较大小
            if(array[child] > array[parent]){
                swap(array,child, parent);
                //比完一组,parent得往下走,动起来
                parent = child;
                child = (2*parent) + 1;
            }else {
                break;
            }
        }

    }

 序总结:
1. 时间复杂度:O(nlogn)
2. 空间复杂度:O(1)
3. 稳定性:不稳定 

三.  交换排序
 

1. 冒泡排序 

这应该是我们最早接触的一种排序,很好理解,不说了 (以前写过)

代码 

/**
     * 冒泡排序
     * @param array
     */
    public static void bubbleSort(int[] array){
        for (int i = 0; i < array.length - 1; i++) {
            boolean flg = false;
            for (int j = 0; j < array.length - 1 - i; j++) {
                if(array[j] > array[j+1]){
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    flg = true;
                }
            }
            if(!flg){
                break;
            }
        }
    }

冒泡排序总结
1. 时间复杂度:O(N^2)
2. 空间复杂度:O(1)
3. 稳定性:稳定 

2.  快速排序
 

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。 

代码(有注释): 

下面介绍两种常用找基准方法 

1.Hoare版 

看上图,直到key(也就是6) 的左边都比key小,右边都比key大

/**
     * 快速排序
     * @param array
     */
    public static void quickSort(int[] array){
        quick(array, 0, array.length - 1);
    }
    private static void quick(int[] array, int start, int end){
        if(start >= end){
            return;
        }
        //防止出现都在一边的情况
        int index = midOfThree(array, start, end);//找到这三个数里(start, mid, end)第二大的下标
        swap(array, start, index);//让start处是这三个里第二大的数
        //找到基准
        int pivot = partition(array, start, end);
        quick(array, start, pivot - 1);
        quick(array, pivot + 1, end);

    }

    private static int partition(int[] array, int left, int right){
        int key = array[left];
        int i = left;
        while(left < right){
            //左边的都比key小,右边的都比key大
            //必须right先走,因为如果是left先走的话,left哪里一定是一个大于key的数,因为left遇到大于key的数才停,之后和right相遇,再换,
            //那左边的被交换数一定是一个大于key的数

            //因为右边应该都是大于key的值,所以要把小于key的数抓出来
            while (left < right && array[right] >= key){
                right--;
            }
            //同理
            while(left < right && array[left] <= key){
                left++;
            }
            swap(array, left, right);
        }
        swap(array, i, left);
        return left;
    }
    private static int midOfThree(int[] array, int left, int right){
        int mid = (left + right)/2;
        if(array[left] > array[right]){
            if(array[mid] > array[left]){
                return left;
            }else if(array[mid] < array[right]){
                return right;
            }else {
                return mid;
            }
        }else {
            if(array[mid] > array[right]){
                return right;
            }else if(array[mid] < array[left]){
                return left;
            }else {
                return mid;
            }
        }
    }
}

2.挖坑法 

 

看上图,直到走完,把pivot按到最后空出的位置,这样 左边都pivot比小,右边都比pivot大了

private static int partition(int[] array, int left, int right) {
    int i = left;
    int j = right;
    int pivot = array[left];//坑挖出来了
    while (i < j) {
        while (i < j && array[j] >= pivot) {
            j--;
        } 
        array[i] = array[j];//坑位变成[j]
        while (i < j && array[i] <= pivot) {
            i++;
        } 
        array[j] = array[i];//坑位变成[i]
    } 
    array[i] = pivot;
    return i;
}

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

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

相关文章

Mysql教程(四):DML学习

Mysql教程&#xff08;四&#xff09;&#xff1a;DML学习 前言 DML-介绍 DML英文全称是Data Manipulation Language数据库操作语言&#xff0c;用来对数据库中表的数据记录进行增删改查。 添加数据&#xff08;INSERT&#xff09;修改数据&#xff08;UPDATE&#xff09;删除…

Java 串口通讯 Demo

为什么写这篇文章 之前职业生涯中遇到的都是通过tcp协议与其他设备进行通讯&#xff0c;而这个是通过串口与其他设备进行通讯&#xff0c;意识到这里是承重板的连接&#xff0c;但实际上比如拉力、压力等模拟信号转换成数字信号的设备应该是有相当一大部分是通过这种方式通讯的…

为你精选5款体验极佳的原型设计工具!

在绘制原型图的过程中&#xff0c;使用一款的简单易操作的原型设计工具是非常重要的&#xff0c;本文精选了5款好用的原型工具与大家分享&#xff0c;一起来看看吧&#xff01; 1、即时设计 即时设计是国内很多设计师都在用的原型设计工具&#xff0c;同时它也是国产的原型设…

JMeter正则表达式提取器和JSON提取器基础用法,小白必会!

最近在利用JMeter做接口自动化测试&#xff0c;正则表达式提取器和JSON提取器用的还挺多&#xff0c;想着分享下&#xff0c;希望对大家的接口自动化测试项目有所启发。 在 JMeter 中&#xff0c;正则表达式和 JSON 提取器都是用于从响应数据中提取所需内容&#xff0c;但它们的…

界面控件Telerik UI for WinForms R2 2023——发布全新的热图控件

Telerik UI for WinForms拥有适用Windows Forms的110多个令人惊叹的UI控件。所有的UI for WinForms控件都具有完整的主题支持&#xff0c;可以轻松地帮助开发人员在桌面和平板电脑应用程序提供一致美观的下一代用户体验。 在本文中&#xff0c;我们将揭秘一下Telerik UI for W…

vue数组对象快速获取最大值和最小值(linq插件各种常用好用方法),提高开发效率

需求&#xff1a;因后端传入的数据过多&#xff0c;前端需要在数组中某一值的的最大值和最小值计算&#xff0c;平常用的最多的不就是遍历之后再比对吗&#xff0c;或者用sort方法等实现&#xff0c;同事交了我一招&#xff0c;一句话就可以获取到数组对象中最大值和最小值&…

【Docker】Docker基本概念

Docker基本概念 1.Docker概述1.1 Docker是什么&#xff1f;1.2 Docker的宗旨1.3 容器的优点1.4 Docker与虚拟机的区别1.5 容器在内核中支持的两种技术1.6 namespace的六大类型 2.Docker核心概念2.1 镜像2.2 容器2.3 仓库 3. 知识点总结3.1 Docker是什么&#xff1f;3.2 容器和虚…

Fortinet Accelerate 2023·中国区巡展收官丨让安全成就未来

7月18日&#xff0c;2023 Fortinet Accelerate Summit在上海成功举办&#xff01;这亦象征着“Fortinet Accelerate2023中国区巡展”圆满收官。Fortinet携手来自多个典型行业的百余位代表客户&#xff0c;以及亚马逊云科技、Telstra - PBS 太平洋电信、Tenable等多家生态合作伙…

RT-Thread 学习-Env开发环境搭建(一)

Env是什么 Env 是 RT-Thread 推出的开发辅助工具&#xff0c;针对基于 RT-Thread 操作系统的项目工程&#xff0c;提供编译构建环境、图形化系统配置及软件包管理功能。 其内置的 menuconfig 提供了简单易用的配置剪裁工具&#xff0c;可对内核、组件和软件包进行自由裁剪&…

PROFIBUS-DP主站转ETHERNET/IP网关ethernet有哪些协议

远创智控YC-DPM-EIP是自主研发的一款PROFIBUS-DP主站功能的通讯网关。该产品主要功能是将各种PROFIBUS-DP从站接入到ETHERNET/IP网络中。 1, 本网关连接到PROFIBUS总线中作为主站使用&#xff0c;连接到ETHERNET/IP总线中作为从站使用。 1.2 产品特点 ◆ PROFIBUS-DP/V0 协议…

AtcoderABC243场

A - Shampoo A - Shampoo ] 题目大意 高桥家有三个人&#xff1a;高桥、他的父亲和他的母亲。每个人每晚都在浴室洗头发。他们按照顺序使用AA、BB和CC毫升的洗发水。 问&#xff0c;今天早上瓶子里有VV毫升的洗发水。在不重新装满的情况下&#xff0c;谁会第一个用完洗发水洗头…

【Maven四】——maven聚合和继承

系列文章目录 Maven之POM介绍 maven命令上传jar包到nexus 【Maven二】——maven仓库 【Maven三】——maven生命周期和插件 聚合和继承 系列文章目录前言一、什么是maven的聚合和继承&why二、聚合三、继承1.可继承的POM元素2.依赖管理3.插件管理 四、聚合与继承的关系五、约…

java电子病历系统源码

电子病历系统采取结构化与自由式录入的新模式&#xff0c;自由书写&#xff0c;轻松录入。化实现病人医疗记录&#xff08;包含有首页、病程记录、检查检验结果、医嘱、手术记录、护理记录等等。&#xff09;的保存、管理、传输和重现&#xff0c;取代手写纸张病历。不仅实现了…

【Docker】Docker安装与操作

docker的安装与命令 一、安装 docker1. 安装依赖包2. 信息查看 二、Docker 镜像操作1. 搜索镜像2. 获取镜像3. 镜像加速下载4. 查看镜像相关信息5. 删除镜像6. 上传镜像7. 存出和载入镜像 三、Docker 容器操作1. 创建容器2. 查看容器3. 启动容器4. 停止容器5. 进入容器6. 容器与…

四、DML-4.小结

一、数据记录操作 1、添加数据 给指定字段添加数据 insert into employee(id, workno, name, gender, age, idcard,entrydate) values (1, 001,Itcast, 男, 18, 123456789012345678, 2023-12-12); INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...); 给全部…

Linux--使用者管理(job control)

Linux–使用者管理(job control) 文章目录 Linux--使用者管理(job control)前言一、任务管理(job control)二、&三、 将目前的任务丢到后台中暂停 -- ctrlz四、jobs -- 查看目前的后台任务状态五、fg -- 将后台任务拿到前台来处理六、bg -- 让任务在后台下的状态变为运行中…

LeetCode 1493. 删掉一个元素以后全为 1 的最长子数组 - 二分 + 滑动窗口

删掉一个元素以后全为 1 的最长子数组 提示 中等 90 相关企业 给你一个二进制数组 nums &#xff0c;你需要从中删掉一个元素。 请你在删掉元素的结果数组中&#xff0c;返回最长的且只包含 1 的非空子数组的长度。 如果不存在这样的子数组&#xff0c;请返回 0 。 提示 1&a…

2023-07-18力扣今日二题-太难了吧

链接&#xff1a; LCP 75. 传送卷轴 题意&#xff1a; 给一个正方形迷宫&#xff0c;主角是A&#xff0c;每次可以上下左右走一格子&#xff0c;有四种类型的格子&#xff1a;墙、初始位置、魔法水晶、空地 另一个人B&#xff0c;可以传送一次A&#xff0c;只能在空地传送&…

Twisted Circuit

题目描述 输入格式 The input consists of four lines, each line containing a single digit 0 or 1. 输出格式 Output a single digit, 0 or 1. 题意翻译 读入四个整数 00 或者 11&#xff0c;作为如图所示的电路图的输入。请输出按照电路图运算后的结果。 感谢PC_DOS …

算法与数据结构-排序

文章目录 一、如何分析一个排序算法1.1 排序算法的执行效率1.1.1 最好情况、最坏情况、平均情况时间复杂度1.1.1.1 最好、最坏情况分析1.1.1.2 平均情况分析 1.1.2 时间复杂度的系数、常数 、低阶1.1.3 比较次数和交换&#xff08;或移动&#xff09;次数 1.2 排序算法的内存消…