【数据结构】八大排序算法(内含思维导图和画图分析)

news2024/11/17 3:37:59

作者主页:paper jie_博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文录入于《JAVA数据结构》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将javaSE基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《算法详解》《C语言》《javaSE》等

内容分享:本期将会分享java数据结构中的排序算法

目录

什么是排序

常见的排序算法

插入排序

基本思想

直接插入排序

具体代码

画图分析

希尔排序

具体代码

画图分析

选择排序

基本思想

直接选择排序

具体代码

画图分析

堆排序

具体代码

画图分析

交换排序

冒泡排序

具体代码

画图分析

快速排序

具体代码

递归版

非递归版

画图分析

归并排序

基本思想

特性

具体代码

递归版

非递归版

画图分析

海量数据的排序处理

排序算法复杂度与稳定性

计数排序

基本思想

具体代码

画图分析

特性


什么是排序

排序:就是让一串数据,按照其中的某个或某些关键字大小,递增或递减排列起来的操作。

内部排序:数据元素全部放在内存中的排序

外部排序:数据元素太多不能同时放在内存中的时候,根据排序过程中的要求不能在内外存之间移动的排序。

稳定性:在经过排序后,这些数据的相对次序还保持不变,则这种排序算法就是稳定的

常见的排序算法

插入排序

基本思想

就是将待排序的记录按关键值的大小一个一个插入已经先排好有序的序列中,直到所有的记录插入完为止,这样就可以得到一个新的有序序列。

我们打牌时的摸牌过程就是这个思想:

直接插入排序

它的操作就是从第二个元素开始向前比较,前面的元素大就交换,把前面的元素比较完,这就是第一轮。然后第二轮就是开始从第三个元素向前比较,以此到最后一个元素。这里比较过后的元素就是有序的了,所以要是在比较的过程中发现前面的元素比比较元素小就不必继续比较下去了,直接进入下一轮。

特点:

元素越有序,直接插入排序的时间效率越来越高

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定

具体代码

//直接插入排序
    /*
    *时间复杂度 O(n^2)
    *空间复杂度 O(1)
    *稳定性: 稳定
     */
public static void initorderSort(int[] array) {
        for(int i = 1; i < array.length; i++) {
            int tmp = array[i];
            int j = 0;
            for(j = i - 1; j >= 0; j--) {
                if(array[j] > array[j+1]) {
                    array[j+1] = array[j];
                }else {
                    break;
                }
                array[j+1] = tmp;
            }
        }
    }

画图分析

希尔排序

它的基本思想就是选定一个整数gap,把需要排序的数据分成若干份,将间隔这个数的数据放在一组,并对每个组进行直接插入排序,这是一轮。然后再重复以上步骤,只不过gap每次/2,知道gao=1时,全部的数据再排序就排好序了。

特性:

希尔排序是对直接插入排序的优化

gap>1时,属于预排序,这样可以让排序更加接近有序。gap==1时,数据就是有序了,这时直接插入排序效率就是会很高

时间复杂度:O(N^1.25~1.6*N^1.25)

空间复杂度:O(1)

稳定性:稳定

具体代码

public static void shellSort(int[] array) {
        int gap = array.length;
        while(gap > 1) {
            gap /= 2;
            shell(array, gap);
        }
    }
    private static void shell(int[] array, int gap) {
        for(int i = gap; i < array.length; i++) {
            int tmp = array[gap];
            int j = 0;
            for (j = i - gap; j >= 0; j-=gap) {
                if(array[j] > tmp) {
                    array[j+gap] = array[j];
                }else {
                    break;
                }
            }
            array[j+gap] = tmp;
        }
    }

画图分析

选择排序

基本思想

每一次从需要排序中的元素中挑出最小的元素放在数据的起始位置,不断重复以上操作,每操作完一轮最小元素放入的位置要往后走一个,直到数全部排序完成。

直接选择排序

在数据中array[i]~array[n-1]中选择最小的元素

将他与这组数据的第一个元素交换

在剩下的array[i]~array[n-1]中,不断重复以上操作

特性:

这个排序易理解,但效率地下,实际很少使用

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:不稳定

具体代码

public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            for (int j = i+1; j < array.length; j++) {
                if(array[minIndex] > array[j]) {
                    minIndex = j;
                }
            }
            int temp = array[i];
            array[i] = array[minIndex];
            array[minIndex] = temp;
        }
    }

画图分析

堆排序

堆排序是指利用堆这种数据结构设计的一种排序算法,它是通过堆来进行的选择数据。排升序是建大堆,排降序建小堆。

特性:

堆排序使用堆来排序,效率就有明显的提高

时间复杂度:O(N*logN)

空间复杂度:O(1)

稳定性:稳定

具体代码

public static void heapSort(int[] array) {
        createHeap(array);
        int end = array.length - 1;
        while(end > 0) {
            int tmp = array[0];
            array[0] = array[end];
            array[end] = tmp;
            siftDowm(array,0, end);
            end--;
        }
    }
    private static void siftDowm(int[]array, int parent, int len) {
        int child = 2*parent + 1;
        while(child < len) {
            if(child+1 < len && array[child+1] > array[child]) {
                child+=1;
            }
            if(array[child] > array[parent]) {
                int tmp = array[child];
                array[child] = array[parent];
                array[parent] = tmp;
                parent = child;
                child = parent*2 + 1;
            }else {
                break;
            }
        }
    }
    private static void createHeap(int[] array) {
        if(array.length == 0) {
            return;
        }
        int parent = (array.length - 1 - 1) / 2;
        for (int i = parent; i >= 0 ; i--) {
            siftDowm(array, parent, array.length);
        }
    }

画图分析

交换排序

基本思想就是根据数据中两个元素的比较结果来交换这两个数据的位置,它的特点就是将值大的元素向后移动,小的向前移动

冒泡排序

冒泡排序就是进行n-1趟比较排序,每一趟都比较n-1次,每比较完一次都减一次比较

特性:

易于理解

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定 

具体代码

 public static void bubbleSort(int[] array) {
        int len = array.length;
        for(int i = 0; i < len - 1; i++) {
            boolean flag = false;
            for(int j = 0; j < len - 1 - i; j++) {
                if (array[j] > array[j+1]) {
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    flag = true;
                }
            }
            if(!flag) {
                break;
            }
        }
    }

画图分析

快速排序

它是一种二叉树结构的交换排序算法。基本思想就是去待排序中的任意一个元素作为基准值,按照这个基准值将数据分割为两个子序列,左边的都小于基准值,右边的都大于基准值,然后左右子序列再重复以上操作,知道最后元素都已经有序。

特性:

快速排序的性能和使用场景都是比较好的

时间复杂度:O(N*logN)

空间复杂度:O(logN)

稳定性:不稳定

具体代码

递归版
  public static void quickSort(int[] array, int start, int end) {
        if(start >= end) {
            return;
        }
        int key = array[start];
        int left = start;
        int right = end;
        while(left < right) {
            while(left < right && array[right] >= key) {
                right--;
            }
            while(left < right && array[left] <= key) {
                left++;
            }
            swap(array, left, right);
        }
        swap(array, start, left);
        //左子树
        quickSort(array, start, left - 1);
        //右子树
        quickSort(array, left+1, end);
    }
非递归版
public static void quickSortnor(int[] array, int start, int end) {
        Stack<Integer> stack = new Stack<>();
        int pivot = partition(array, start, end);
        if(pivot- 1 > start) {
            stack.push(start);
            stack.push(pivot - 1);
        }
        if(pivot+1 < end) {
            stack.push(pivot + 1);
            stack.push(end);
        }

        while(!stack.isEmpty()) {
            int right = stack.pop();
            int left = stack.pop();
             pivot = partition(array, left, right);
            if(pivot - 1 > left) {
                stack.push(start);
                stack.push(pivot - 1);
            }
            if(pivot+1 < right) {
                stack.push(pivot + 1);
                stack.push(end);
            }
        }
     }
    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];
            while (i < j && array[i] <= pivot) {
                i++;
            } 
        array[j] = array[i];
        } 
        array[i] = pivot;
        return i;
    }

画图分析

递归:

非递归:

归并排序

基本思想

归并排序是建立在归并操作上的一种有效的排序算法,它采用的是分治法,将已有序的序列合并,得到完全有序的序列。就是先让子序列有序,再使子序列何合并有序,这样叫做二路归并。

特性

归并排序的缺点在于需要O(N)的空间复杂度,归并排序的思考是解决在磁盘中的外存排序问题

时间复杂度:O(N*logN)
空间复杂度:O(N)
稳定性:稳定

具体代码

递归版

//归并排序
    /*
     *时间复杂度:O(n*logn)
     *空间复杂度 O(logn)
     *稳定性:稳定
     */
    public static void mergeSort(int[] array, int start, int end) {
        if(start >= end) {
            return ;
        }
        //分解
        int mid = (start + end) / 2;
        mergeSort(array,start, mid);
        mergeSort(array, mid+1, end);
        //合并
        merge(array, start, mid, end);
    }

    private static void merge(int[] array, int start, int mid, int end) {
        int s1 = start;
        int s2 = mid;
        int e1 = mid+1;
        int e2 = end;
        int i = 0;
        int[] arr = new int[end - start + 1];
        while(s1 <= s2 && e1<=e2) {
            if(array[s1] < array[e1]) {
                arr[i++] = array[s1++];
            }else {
                arr[i++] = array[e1++];
            }
        }
        while(s1 <= s2) {
            arr[i++] = array[s1++];
        }
        while(e1 <= e2) {
            arr[i++] = array[e1++];
        }
        //把排好序的数组放到原来的数组中
        for (int j = 0; j < arr.length; j++) {
            array[j+start] = arr[j];
        }
    }

非递归版

public static void mergesortNor(int[] array) {
        int gap = 1;
        while(gap < array.length) {

            for (int i = 0; i < array.length; i+=2*gap) {
                int left = i;
                int mid = left + gap - 1;
                int right = mid + gap;

                //防止越界
                if(mid >= array.length) {
                    mid = array.length - 1;
                }
                if(right >= array.length) {
                    right = array.length - 1;
                }
                merge(array, left, mid, right);
            }

            gap*=2;
        }
    }

画图分析

递归:

非递归:

海量数据的排序处理

外部排序:排序过程需要在磁盘等外部存储进行的排序

前提:内存只有一个G,需要排序的数据有100G

因为内存中无法把所有的数据发放下,所以需要外部排序,归并排序就是最常用的外部排序

处理方式:

先将文件分成200份,每个512M

分别对512M排序,因为内存已经可以放的下,排序

进行2路归并,堆200份文件过归并过程,最后就会有序

排序算法复杂度与稳定性

计数排序

基本思想

计数排序是对哈希直接定址法的应用

1 统计相同的元素次数

2 根据统计的结果将序列回收到原来的序列中

具体代码

 public static void countSort(int[] array) {
        //确定长度
        int max = 0;
        int min = 0;
        for (int i = 0; i < array.length; i++) {
            if(array[i] > max) {
                max = array[i];
            }
            if(array[i] < min) {
                min = array[i];
            }
        }
        int[] count = new int[max - min + 1];
        int j = 0;
        //将相同的数的次数存储到计数数组中
        for(int i = 0; i < array.length; i++) {
            count[array[i] - min]++;
        }
        //遍历计数数组 把实际的数据写到array中
        for (int i = 0; i < count.length; i++) {
            while(count[i] > 0) {
                array[j++] = i+min;
                count[i]--;
            }
        }
    }

画图分析

特性

计数排序在数据范围集中时,效率很高,但是这种情况比较少

时间复杂度:O(范围)

空间复杂度:O(范围)

稳定性:稳定

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

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

相关文章

跳表:为什么Redis一定要用跳表来实现有序集合

文章来源于极客时间前google工程师−王争专栏。 二分查找底层依赖的是数组随机访问的特性&#xff0c;所以只能用数组来实现。如果数据存储在链表中&#xff0c;就真的没法使用二分查找算法了吗&#xff1f; 我们可以对链表稍加改造&#xff0c;就可以支持类似“二分”的查找算…

LVGL_文件系统FS

LVGL_文件系统FS 前言&#xff1a; LVG 内置支持以下文件系统&#xff1a; 1、FATFS 2、STDIO (Linux 和 Windows 都可以使用的 C 标准函数接口&#xff0c;比如&#xff1a;fopen, fread…) 3、POSIX (Linux 和 Windows 都可以使用的 POSIX 函数接口&#xff0c;比如&#xff…

vue3 element-plus 组件table表格 勾选框回显(初始化默认回显)完整静态代码

<template><el-table ref"multipleTableRef" :data"tableData" style"width: 100%"><el-table-column type"selection" width"55" /><el-table-column label"时间" width"120">…

Go学习第三章——运算符与进制

Go学习第三章——运算符与进制 1 算术运算符2 关系运算符3 逻辑运算符4 赋值运算符5 其他运算符5.1 位运算符5.2 跟指针有关的运算符 6 运算符的优先级7 获取用户终端输入8 进制转换8.1 进制基本使用8.2 进制之间的转换8.3 原码 反码 补码8.4 位运算符详解 运算符是—种特殊的符…

KubeSphere一键安装部署K8S集群(单master节点)-亲测过

1. 基础环境优化 hostnamectl set-hostname master1 && bash hostnamectl set-hostname node1 && bash hostnamectl set-hostname node2 && bashcat >> /etc/hosts << EOF 192.168.0.34 master1 192.168.0.45 node1 192.168.0.209…

python查询数据库发送邮件,附件csv格式,xlsx格式

# 设置liunx系统运行python代码的解释器 #!/usr/bin/python3# python声明文件的编码格式为UTF-8 # python2默认以ASCII编码来读取文件&#xff0c;如果不声明编码格式&#xff0c;它可能会无法正确地解析非ASCII字符&#xff08;比如中文字符&#xff09;。 # python3开始默认支…

【ACO-KELM预测】基于蚁群算法优化核极限学习机回归预测研究(matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

VS Code C# 开发工具包正式发布

前言 微软于本月正式发布Visual Studio Code C#开发工具包&#xff0c;此前该开发套件已经以预览版的形式在6月份问世。经过4个月的测试和调整&#xff0c;微软修复了350多个问题&#xff0c;其中大部分是用户反馈导致的问题。此外&#xff0c;微软还对产品进行了300多项有针对…

【MicroSoft Edge】格式化的显示JSON格式的数据

当我们没有进行任何操作的时候&#xff0c;默认浏览器给我们展示的JSON的数据是这样的&#xff1a; 看着十分不便。 解决方案&#xff1a; 首先点击 MicroSoft Edge 浏览器右上角的三点&#xff0c;如何选择扩展 点击 获取Microsoft Edge 扩展 搜索 JSONView&#xff0c;第一…

智慧公厕系列产品:为您提供更便捷、更卫生的厕所体验

智慧公厕系列产品致力于改善公共厕所的管理和使用体验&#xff0c;通过引入先进的科技和智能设备&#xff0c;提升厕所的安全、卫生、舒适性。这些产品涵盖了从厕位监测到环境调控&#xff0c;从安全防范到能耗监测的各个方面&#xff0c;为用户提供了一个更加方便、舒适、卫生…

【每日一题】做菜顺序

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;贪心排序 写在最后 Tag 【贪心排序】【数组】【2023-10-22】 题目来源 1402. 做菜顺序 题目解读 每一道菜都有一个满足程度&#xff08;是一个整数&#xff09;&#xff0c;制作完成每道菜的时间为 1&#xff0c;每一…

Xray联动RAD实现自动扫描教程

Rad下载地址&#xff1a;https://github.com/chaitin/rad xray下载地址&#xff1a;https://github.com/chaitin/xray Xray启动监听&#xff1a; xray_windows_amd64.exe webscan --listen 127.0.0.1:7777 --html-output xray-xxx.html RAD启动爬虫抓包&#xff1a; rad_win…

反射、枚举及lambda表达式

文章目录 一、反射1.1 定义和用途1.2 反射基本信息1.3 反射相关的类&#xff08;重要&#xff09;1.4 Class类&#xff08;反射机制的起源&#xff09;1.5 反射优缺点1.6 总结 二、枚举2.1 定义2.2 使用2.3 枚举优缺点2.4 枚举和反射2.5 总结 三、lambda表达式3.1 背景3.2 基本…

家庭WIFI路由器、无线网卡购买指南

一、参考资料 【Wi-Fi】802.11/802.11b/802.11g/802.11n/802.11a/802.11ac/802.11ax/802.11be 从带宽到路由&#xff0c;从有线到无线&#xff0c;从需求到选购&#xff0c;从布网到实测&#xff0c;全部说尽。基础篇&#xff08;1&#xff09; 【一文详解】802.11a/b/g/n/ac/…

【28】c++设计模式——>观察者模式(1)

观察者模式概念 C观察者模式&#xff08;Observer Pattern&#xff09;是一种设计模式&#xff0c;它用于在对象之间建立一种一对多的依赖关系。在该模式中&#xff0c;当一个对象&#xff08;称为主题&#xff09;发生变化时&#xff0c;所有依赖于它的对象&#xff08;称为观…

跳跃游戏Ⅱ-----题解报告

题目&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 与Ⅰ不同的是&#xff0c;这次要求找出最小的跳跃次数。思路也很简单&#xff0c;在每一次跳跃之后都更新最远的跳跃距离。 举个列子&#xff1a; 输入&#xff1a;2,3,1,1,4 第一次…

【SSA-BP预测】基于麻雀算法优化BP神经网络回归预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Linux 中监控磁盘分区使用情况的 10 个工具

在本文[1]中&#xff0c;我们将回顾一些可用于检查 Linux 中磁盘分区的 Linux 命令行实用程序。 监控存储设备的空间使用情况是系统管理员最重要的任务之一&#xff0c;它可以确保存储设备上有足够的可用空间&#xff0c;以维持 Linux 系统的高效运行。 1. fdisk fdisk 是一个强…

STM32+摁键与定时器实现Led灯控制(中断)

中断作为单片机开发必须掌握的内容&#xff0c;它能够在不搭载操作系统的情况下让我们体验多任务处理的快感&#xff0c;保证了高优先级任务的实时性&#xff0c;同时系统中断也能够提供给用户在核心发生错误之后进行处理的机会。STM32F103系列单片机中断非常强大&#xff0c;每…

SpringBoot +JdbcTemplate+VUE 实现在线输入SQL语句返回数据库结果

文章目录 前言框架选型SpringBoot 结合JdbcTemplate简单示例SpringBoot 结合JdbcTemplate实现运行SQL处理思路后端处理前端处理 前言 想起来要做这个功能是因为我们公司的预生产环境和生产环境如果想要连接数据库都需要登录堡垒机&#xff0c;然后再通过堡垒机进行跳转到对应定…