十大排序算法(Java实现)

news2024/12/25 0:27:25

文章目录

  • 零、总览 / 前言
  • 一、冒泡排序
    • 1.算法描述
    • 2.代码&复杂度
  • 二、选择排序
    • 1.算法描述
    • 2.代码&复杂度
  • 三、插入排序
    • 1.算法描述
    • 2.代码&复杂度分析
  • 四、希尔排序
    • 1.算法步骤
    • 2.代码&复杂度分析
  • 五、归并排序
    • 1.算法描述
    • 2.代码&复杂度分析
  • 六、快速排序
    • 1.算法描述
    • 2.代码&复杂度分析
  • 七、堆排序
  • 八、计数排序——非比较排序
    • 1.算法描述
    • 2.代码&复杂度分析
  • 九、基数排序——非比较排序
  • 十、桶排序——非比较排序

零、总览 / 前言

在这里插入图片描述

复杂度和稳定性表格一览

排序算法平均时间最好时间最坏时间空间稳定性
冒泡 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
选择 O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)不稳定
插入 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
希尔 O ( 1 ) O(1) O(1)不稳定
归并 O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n ) O(n) O(n)稳定
快排 O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n 2 ) O(n^2) O(n2) O ( l o g n ) O(logn) O(logn)不稳定
堆排序 O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( 1 ) O(1) O(1)不稳定
计数排序 O ( n + k ) O(n+k) O(n+k) O ( n + k ) O(n+k) O(n+k) O ( n + k ) O(n+k) O(n+k) O ( n + k ) O(n+k) O(n+k)稳定
基数排序稳定
桶排序 O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)稳定

解释一下稳定性:
对于存在相等元素的序列,排序后,原相等元素在排序结果中的 相对位置 相比原输入序列不变
例如 nums={3,1, 2 1 2_1 21, 2 2 2_2 22} ,数字 2 出现了两次,下标表示他们出现的次序,若排序方法将 nums 排成了 {1, 2 2 2_2 22​ , 2 1 ​ 2_1​ 21 ,3} ,虽然排序结果正确,但改变了两个 2 的相对位置。只有排序为 {1, 2 1 2_1 21, 2 2 2_2 22,3} 我们才说该排序是稳定的。

如果排序对象只是数值,那么是否稳定没有区别。但若是对引用类型进行排序,排序依据是该类型中的某个可比较的数值字段,那么我们可能会希望该字段相同,但其他字段不同的元素相对位置相比原输入保持不变,这时候就需要稳定排序。

不稳定排序算法
堆排序、快速排序、希尔排序、直接选择排序

稳定排序算法
基数排序、冒泡排序、插入排序、归并排序

一、冒泡排序

1.算法描述

对于要排序的数组,从第一位开始从前往后比较相邻两个数字,若前者大,则交换两数字位置,然后比较位向右移动一位。第1轮从前到后的比较将使得最大的数字 冒泡 到最后

接着第二轮,同样的操作,只不过只需要比到倒数第二个(倒数第一已经最大了)

重复以上操作……

2.代码&复杂度

//冒泡排序,从小到大排序,比较相邻元素,更大的往数组右边移动
    static void bubbleSort3(int[] arr)
    {
        for(int i=arr.length-1;i>0;i--)
        {
            for(int j=0;j<i;j++)
            {
                if(arr[j]>arr[j+1])
                {
                    int tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                }
            }
        }
    }

时间复杂度:O(n^2)
空间复杂度:O(1)

二、选择排序

1.算法描述

步骤:
(1)长度为n的数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换

(2)第二次遍历n-2个数,找到最小的数值与第二个元素交换

(3)第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成

2.代码&复杂度

 public void selectSort3(int[] arr)
    {
        for(int i=0;i<arr.length;i++)
        {
            int minTmp = Integer.MAX_VALUE;
            int index=0;
            // 开始寻找本轮最小的数字
            for(int j=i;j<arr.length;j++)
            {
                if(minTmp>arr[j])
                {
                    // 每次找到更小的时候记录数字和下标值
                    minTmp = arr[j];
                    index = j;
                }
            }
            // 本轮循环结束,将最小值交换到数组前方
            int temp = arr[i];
            arr[i] = minTmp;
            arr[index] = temp;
    }

时间复杂度:O(n^2)
空间复杂度:O(1)

三、插入排序

1.算法描述

插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列

算法步骤:
(1)将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。

(2)从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。

2.代码&复杂度分析

 /*插入排序:从小到大排序,类似于打扑克牌*/
    static void insertSort(int[] arr)
    {
        for(int i=1;i<arr.length;i++)
        {
            int now=arr[i]; //刚抓的手牌
            int j=i-1; //现有最后一张手牌的位置
            while (j>=0 && now<arr[j])  //刚抓的手牌小于手上现有的
            {
                arr[j+1]=arr[j];
                j--;
            }
            arr[j+1]=now;
        }
    }

时间复杂度:O(n^2)—— i 遍历一次,j遍历了一次,所以n^2
空间复杂度:O(1)—— 原地修改,没有用额外空间

四、希尔排序

1.算法步骤

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。

2.代码&复杂度分析

  //希尔排序:从小到大
  static void shellSort(int[] arr)
  {
      for(int interval=arr.length/2;interval>0;interval=interval/2)
      {
          for(int i=interval;i<arr.length;i++)
          {
              int temp=arr[i]; //从中间开始
              int j=i-interval; //增量是interval的前面的一个元素
              while (j>=0 && temp<arr[j])
              {
                  arr[j+interval]=arr[j];
                  j-=interval;
              }
              arr[j+interval]=temp;
          }
      }
  }

时间复杂度:
空间复杂度:

五、归并排序

1.算法描述

分而治之,先分治,再合并

2.代码&复杂度分析

public static void main(String[] args) {
        int[] arr = {5, 3, 8, 6, 2, 7};
        mergeSort(arr, 0, arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
       // 自顶向下,递归实现
        public static void mergeSort(int[] arr, int left, int right) {
            if (left < right) {
                int mid = (left + right) / 2;
                mergeSort(arr, left, mid);
                mergeSort(arr, mid+1, right);
                merge(arr, left, mid, right);
            }
        }

        // 非原地合并
        public static void merge(int[] arr, int left, int mid, int right) {
            int[] temp = new int[arr.length];
            int i = left;
            int j = mid + 1;
            int k = left;
            while (i <= mid && j <= right) {
                if (arr[i] <= arr[j]) {
                    temp[k++] = arr[i++];
                } else {
                    temp[k++] = arr[j++];
                }
            }
            while (i <= mid) {
                temp[k++] = arr[i++];
            }
            while (j <= right) {
                temp[k++] = arr[j++];
            }
            for (int m = left; m <= right; m++) {
                arr[m] = temp[m];
            }
        }

六、快速排序

1.算法描述

首先在数组中确定一个主轴元素 (一般以第一个元素为主轴元素),然后遍历数组,将数组分为两部分, 小于 主轴的元素放在 (最终的) 主轴下标 p 的左侧, 大于等于 主轴的放在右侧。

具体每一轮的操作过程是:
双指针的思想,左指针指向第一个元素,右指针指向最后一个元素。左指针的目标是找到比主轴元素大的,找到后指针就停止,右指针则相反。当两者都找到后,就进行交换。然后继续这个过程,知道两指针相遇。

贴一个简单易懂的快排的排序过程:https://blog.csdn.net/qq_40941722/article/details/94396010

2.代码&复杂度分析

void quickSort(int[] arr,int left,int right)
    {
        if(left>right)
            return;
        int pivot=arr[left];
        int i=left;
        int j=right;
        while(i!=j)
        {
            while (i<j && arr[j]>=pivot)
                j--;
            while(i<j && arr[i]<=pivot)
                i++;
            if(i<j)
            {
                int temp=arr[j];
                arr[j]=arr[i];
                arr[i]=temp;
            }
        }
        arr[left]=arr[i];
        arr[i]=pivot;

        quickSort(arr,left,i-1);
        quickSort(arr,i+1,right);
    }

时间复杂度:O(nlogn)
空间复杂度:O(logn)

七、堆排序

八、计数排序——非比较排序

1.算法描述

计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。通常 适用于整数数组,是一种利用整数特点取得 线性复杂度非比较排序方法

算法步骤:
(1)找出待排序的数组中最大max和最小min的元素

(2)创建一个计数数组 countArr ,其大小为 arrarr 中的max-min+1

(3)统计数组中每个值为i的元素出现的次数,每读取一个arr[i] ,直接令countArr[arr[i]-min]++

(4) 遍历countArr ,依次输出 counter[i] 个 i ,即为排序结果

2.代码&复杂度分析

static int[] countSort(int[] arr)
    {
        int minNum=0,maxNum=0;
        // 先求出数组中的最大值和最小值
        for (int num : arr) {
            minNum = Math.min(minNum, num);
            maxNum = Math.max(maxNum, num);
        }
        // 开辟一个新数组:计数数组
        int[] count = new int[maxNum-minNum+1];
 
        // 遍历原数组,对应计数数组索引值++
        for(int num:arr)
        {
            count[num-minNum]++;
        }
        // 开始将计数数组输出
        int index=0;
        for(int i=0;i<count.length;i++)
        {
            while(count[i]>0)
            {
                arr[index++] = i;
                count[i]--;
            }
        }
        return arr;
    }

时间复杂度: O(n + k),n 为元素个数, k 计数数组大小

空间复杂度:O(k)

上面的还是属于不稳定版本的,稳定版本可以参见:https://leetcode.cn/circle/discuss/eBo9UB/

九、基数排序——非比较排序

十、桶排序——非比较排序

参考链接:https://leetcode.cn/circle/discuss/eBo9UB/

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

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

相关文章

《强化学习的数学原理》思维导图,供初学者参考

对应课程&#xff1a; 【强化学习的数学原理】课程&#xff1a;从零开始到透彻理解&#xff08;完结&#xff09;_哔哩哔哩_bilibili

Linux 系统下 CMake 示 例

CMake 是一个开源的跨平台工具&#xff0c;可以构建、测试和打包软件。 它具有如下特性&#xff1a; 自动搜索可能需要的程序、库和头文件的能力&#xff1b;独立的构建目录&#xff08;如build&#xff09;&#xff0c;可以安全清理&#xff1b;支持复杂的自定义命令&#xf…

一文了解什么什么是加密货币及其工作原理

加密货币是基于区块链技术并由密码学保护的去中心化数字货币。要理解加密货币&#xff0c;首先需要理解三个术语——区块链、去中心化和密码学。 一、加密货币如何运作 简而言之&#xff0c;加密货币中的区块链是一种数字分类账&#xff0c;其访问权限分布在授权用户之间。该分…

hello算法学习笔记之排序

概述&#xff1a;排序算法 在排序算法中&#xff0c;数据类型可以是整数、浮点数、字符或字符串等&#xff1b;顺序的判断规则可根据需求设定&#xff0c;如数字大小、字符 ASCII 码顺序或自定义规则。 评价维度&#xff1a; 运行效率、就地性、稳定性、自适应性&#xff08…

21.RocketMQ源码之NameServer的路由管理和架构设计

highlight: arduino-light NameServer 路由管理 Broker消息服务器在启动的时向所有NameServer注册。 消息生产者Producer在发送消息之前先从NameServer获取Broker服务器地址列表然后根据负载均衡算法从列表中选择一台服务器进行发送。 NameServer与每台Broker保持长连接&#x…

单频/双频gps北斗模块相关应用领域详解_SKYLAB GPS+北斗模块

以“时空数据&#xff0c;赋能未来”为主题的第十二届中国卫星导航年会在江西南昌正式开幕&#xff0c;据悉&#xff0c;本届年会是北斗系统开启全球化、产业化的第一届年会。2020年&#xff0c;北斗三号全球卫星定位系统正式服务全球&#xff0c;作为北斗产业链中的一员&#…

小黑厦门极限神游,通宵环岛骑行,鼓浪屿徒步赏景的leetcode之旅:剑指 Offer 48. 最长不含重复字符的子字符串

小黑代码(与官方题解思路一致&#xff0c;比其可读性更强) class Solution:def lengthOfLongestSubstring(self, s: str) -> int:# 字符串长度n len(s)# 定义双指针head 0tail 0# 中间变量&#xff0c;存放窗口中的元素set_ set()# 结果变量length 0while tail < n…

Flutter iOS 打包 问题处理

日常问题收集&#xff1a; remark: Incremental compilation has been disabled: is not currently compatible with embedding LLVM IR bitcode a. 在Build Settings中搜索Enable Bitcode-> 设置No b. Project-> Targets-> Build Settings-> Custom Compiler Flag…

银行数字化转型导师坚鹏:银行数字化运营所必须采取的五大措施

银行数字化运营已经成为提升市场竞争力和客户满意度的重要战略。以下是银行数字化运营所必须采取的五大措施&#xff1a; 1) 建立强大的数字化基础设施&#xff1a;银行需要投资建立可靠的数字化基础设施&#xff0c;以支持数字化运营的各个方面。这包括更新和升级银行的IT系统…

springboot集成openfeign

一、Feign简介 Feign是一个声明式的伪Http客户端&#xff0c;它使得写Http客户端变得更简单。使用Feign&#xff0c;只需要创建一个接口并注解。它具有可插拔的注解特性&#xff0c;可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon&…

Django - 定时任务框架【django-apscheduler】基本使用详解(二)

一. 前言 一个网页会有很多数据是不需要经常变动的&#xff0c;比如说首页&#xff0c;变动频率低而访问量大&#xff0c;我们可以把它静态化&#xff0c;这样就不需要每次有请求都要查询数据库再返回&#xff0c;可以减少服务器压力 我们可以使用Django的模板渲染功能完成页面…

【Android Framework系列】第4章 PMS原理

1 PMS简介 PMS&#xff08;PackageManagerService&#xff09;是Android提供的包管理系统服务&#xff0c;它用来管理所有的包信息&#xff0c;包括应用安装、卸载、更新以及解析AndroidManifest.xml。通过解析每个安装应用的AndroidManifest.xml&#xff0c;将xml中的数据全部…

Acwing.846 数的重心(DFS)

题目 给定一颗树&#xff0c;树中包含n个结点&#xff08;编号1~n)和n-1条无向边。 请你找到树的重心&#xff0c;并输出将重心删除后&#xff0c;剩余各个连通块中点数的最大值。 重心定义:重心是指树中的一个结点&#xff0c;如果将这个点删除后&#xff0c;剩余各个连通块中…

Java项目实战——Linux入门

文章目录 一、Linux安装1.1、安装方式介绍1.2、网卡设置1.3、安装SSH连接工具1.4、Linux和windows目录结构对比1.5、Linux目录结构 2、Linux常用命令2.1、Linux命令初体验2.2、使用技巧2.3、命令格式2.4、文件目录操作命令文件目录操作命令ls小知识 文件目录操作命令cat文件目录…

数据倾斜排查

一、问题现象 租户反馈&#xff0c;任务执行时长加长&#xff0c;执行过程中任务卡在 99%&#xff0c;大概率是出现了数据倾斜 二、排查过程 数据倾斜大多数都是大 key 问题导致的。排查方法如下&#xff1a; 1.时间判断 reduce 的时间比其他 reduce 时间长的多&#xff0c;大…

基于STM32的户外环境监测系统的设计

目录 1 引言 1.1 本课题的研究意义 1.2 本课题的研究现状 1.3本课题的发展趋势和研究可行性 1.4本课题主要研究工作 2 系统的概述和相关原理 2.1 系统的概述 2.1.1 总体设计的方案 2.1.2 总体框图 2.2 相关理论 2.2.1 STM32平台 2.2.2 WIFI模块 3 硬件电路设计 8 3…

解决页面等比缩放问题

近些年可视化数据大屏技术早已成熟&#xff0c;在市场上相关技术也是五花八门&#xff1b;通常情况是自行开发&#xff0c;要不找技术比较成熟大厂定制&#xff0c;或者使用较成熟的低代码平台实现。 技术门槛比较低&#xff0c;不过在数据大屏项目实施过程中会发现&#xff0c…

《移动互联网技术》第一章 概述: 掌握移动互联网的基本概念和组成

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

密码找回安全总结-业务安全测试实操(28)

撞库攻击 撞库是黑客通过收集互联网已泄露的用户和密码信息,生成对应的字典表,尝试批量登录其他网站后,得到一系列可以登录的用户名和密码组合。由于很多用户在不同网站使用的是相同的账号和密码,因此黑客可以通过获取用户在 A 网站的账户从而尝试登录B网站,这就可以理解为…

Linux--时间相关的指令:date、cal

一、data显示 date 指定格式显示时间&#xff1a; date %Y:%m:%d date 用法&#xff1a; date [OPTION]... [FORMAT] 1.在显示方面&#xff0c;使用者可以设定欲显示的格式&#xff0c;格式设定为一个加号后接数个标记&#xff0c;其中常用的标记列表如下 %H : 小时(00..2…