排序算法:插入排序、冒泡排序、选择排序、希尔排序、堆排序、快速排序、归并排序

news2025/2/21 23:04:59

排序算法相关总结,涉及的排序算法有:插入排序、冒泡排序、选择排序、希尔排序、堆排序、快速排序、归并排序(动图不是自己画的🌞)。

目录

      • 1.插入排序
      • 2.冒泡排序
      • 3.选择排序
      • 4.希尔排序
      • 5.堆排序
      • 6.快速排序
      • 7.归并排序
      • 总结


稳定性概念:
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i] = r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的,否则称为不稳定的。


1.插入排序

思路:当前元素左边为有序序列,右边为待排序序列,当前元素与有序数列的最后一个元素依次比较,如果比它大,则不动,若比它小,则有序序列最后一个元素后移一位,为当前元素空出一个坑位,循环比较,直到找到当前元素的位置。

图示:

在这里插入图片描述

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

//插入排序

public class InsertSort {
    public static void main(String[] args) {
        //验证
        int[] arr = new int[]{5, 4, 3, 8, 4, 1, 6, 0, 9, 10};
        insertSort(arr);
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }

    //插入排序
    public static void insertSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            //有序区间为 [0,i)
            int k = i;
            //记录i下标当前值 与有序序列比较
            int tmp = arr[i];
            //如果下标合法且比tmp大 则元素后移
            while (k > 0 && tmp < arr[k - 1]) {
                arr[k] = arr[k - 1];
                k--;
            }
            arr[k] = tmp;
        }
    }

2.冒泡排序

冒泡!!!好的解释完了

图示:
在这里插入图片描述

代码: 老老老朋友了,时间复杂度O(n^2),空间复杂度O(1)

//冒泡排序

public class BubbleSort {
    public static void main(String[] args) {
        //验证
        int[] arr = new int[]{5, 4, 3, 8, 4, 1, 6, 0, 9, 10};
        bubblesort(arr);
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }

    //冒泡排序
    public static void bubblesort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            //判断该趟是否发生交换
            boolean flag = true;
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    //交换
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;
                    flag = false;
                }
            }
            //如果没有发生交换 则说明后面的已经有序 结束循环
            if (flag) {
                break;
            }
        }
    }

3.选择排序

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

图示:
在这里插入图片描述

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

//选择排序(将找到的较大元素放置末尾 和上图演示的反着的 但不影响理解)

public class SelectSort {
    public static void main(String[] args) {
        //验证
        int[] arr = new int[]{5, 4, 3, 8, 4, 1, 6, 0, 9, 10};
        selectSort(arr);
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }

    public static void selectSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int maxIdx = 0;
            for (int j = 1; j < arr.length - i; j++) {
                if (arr[j] > arr[maxIdx]) {
                    maxIdx = j;
                }
            }
            //swap
            int idx = arr.length - 1 - i;
            int tmp = arr[maxIdx];
            arr[maxIdx] = arr[idx];
            arr[idx] = tmp;
        }
    }

4.希尔排序

我们知道插入排序元素越有序效率越高,当全部有序时,效率达到O(n),希尔排序正是利用这个特点,进行了大量的分组插入排序,从而达到有序目的。
基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后取重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

图示:

在这里插入图片描述

动图:

在这里插入图片描述

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

//希尔排序

public class ShellSort {
    public static void main(String[] args) {
        //验证
        int[] arr = new int[]{5, 4, 3, 8, 4, 1, 6, 0, 9, 10, -5, 50, 33, 41, 7, 30, 45, 11};
        shellSort(arr);
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }

    public static void shellSort(int[] arr) {
        if (arr.length == 0 || arr.length == 1) {
            return;
        }
        int gap = arr.length / 2;
        while (true) {
            for (int i = gap; i < arr.length; i++) {
                int tmp = arr[i];
                int k = i;
                while (k - gap >= 0 && tmp < arr[k - gap]) {
                    arr[k] = arr[k - gap];
                    k -= gap;
                }
                arr[k] = tmp;
            }
            if (gap == 1) {
                break;
            }
            gap /= 2;
        }
    }

5.堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。

图示:
在这里插入图片描述

代码: 时间复杂度O(N*log(N)),空间复杂度O(1)

//堆排序

public class HeapSort {
    public static void main(String[] args) {
        //验证
        int[] arr = new int[]{5, 4, 3, 8, 4, 1, 6, 0, 9, 10, -5, 50, 33, 41, 7, 30, 45, 11};
        heapSort(arr);
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }

    public static void heapSort(int[] arr) {
        //建堆
        createHeap(arr);
        for (int i = 0; i < arr.length - 1; i++) {
            swap(arr, 0, arr.length - 1 - i);
            adjustDown(arr, 0, arr.length - 1 - i);
        }
    }

    public static void createHeap(int[] arr) {
        for (int i = (arr.length - 1 - 1) / 2; i >= 0; i--) {
            adjustDown(arr, i, arr.length);
        }
    }

    //在无序区间内进行向下调整
    public static void adjustDown(int[] arr, int idx, int len) {
        while (2 * idx + 1 < len) {
            int maxIdx = 2 * idx + 1;
            int rightIdx = maxIdx + 1;
            if (rightIdx < len && arr[maxIdx] < arr[rightIdx]) {
                maxIdx = rightIdx;
            }
            if (arr[maxIdx] < arr[idx]) {
                break;
            }
            swap(arr, maxIdx, idx);
            //更新
            idx = maxIdx;
        }
    }

    private static void swap(int[] arr, int i, int j) {
        //swap
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

6.快速排序

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

代码:时间复杂度O(n*logn),空间复杂度O(log n) ~ O(n)

    public static void quickSort(int[] arr, int from, int to) {
        //判断是否结束
        if (to - from < 1) {
            return;
        }
        //划分方法 下面有实现
        int div = partition(arr, from, to);
        quickSort(arr, from, div - 1);
        quickSort(arr, div + 1, to);
    }

将区间按照基准值划分为左右两半部分的常见方式有:

1.Hoare:

1.选出一个基准值pivot,一般是最左边或最右边的为基准值
2.找到右边第一个小于pivot的值
3.找到左边第一个大于pivot的值
4.交换两个值,然后重复步骤2、3
5.将基准值放到i == j 的位置,返回基准值下标

    public static int partition(int[] arr, int left, int right) {
        int i = left;
        int j = right;
        int pivot = arr[left];
        while (i < j) {
            //注意这里判断j与先判断i的区别
            //先判断j:当i == j时 arr[i] == arr[j] <= povit
            //先判断i:当i == j时 arr[i] == arr[j] >= povit
            while (i < j && arr[j] >= povit) {
                j--;
            }
            while (i < j && arr[i] <= povit) {
                i++;
            }
            swap(arr, i, j);
        }
        swap(arr, left, i);
        return i;
    }

图示:
在这里插入图片描述

2.挖坑法:

1.选出一个基准值pivot,一般是最左边或最右边的为基准值 让它做坑位
2.找到右边第一个小于pivot的值 将该值放入坑位 该值的原下标做为新坑位
3.找到左边第一个大于pivot的值 将该值放入坑位 该值的原下标做为新坑位
4.重复步骤2、3
5.将基准值放到i == j 的位置,返回基准值下标

    public static int partition(int[] arr, int left, int right) {
        int i = left;
        int j = right;
        int pivot = arr[left];
        while (i < j) {
            while (i < j && arr[j] >= pivot) {
                j--;
            }
            arr[i] = arr[j];
            while (i < j && arr[i] <= pivot) {
                i++;
            }
            arr[j] = arr[i];
        }
        arr[i] = pivot;
        return i;
    }

图示:

在这里插入图片描述

3.前后指针法:

1.选出一个基准值pivot,一般是最左边或最右边的为基准值
2.规定[0,pre)为小于pivot的范围,[pre,right]为大于pivot的范围
3.遍历找小于pivot的值,交换arr[pre]和该值,然后pre++
4.最后将pivot值放入数组,放哪里合适呢?当然是pre - 1处,这样确保它的右边大于等于pivot,左边小于等于pivot

    public static int partition(int[] arr, int left, int right) {
        int pre = left + 1;
        int pivot = arr[left];
        for (int cur = pre; cur <= right; cur++) {
            if (arr[cur] < pivot) {
                swap(arr, cur, pre);
                pre++;
            }
        }
        swap(arr, pre - 1, left);
        return pre - 1;
    }

7.归并排序

基本思想:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

图示:

在这里插入图片描述

动图:

在这里插入图片描述
代码:时间复杂度O(n*logn),空间复杂度O(n)

//归并排序

public class MergeSort {
    public static void main(String[] args) {
        //验证
        int[] arr = new int[]{5, 4, 3, 8, 4, 1, 6, 0, 9, 10, -5, 50, 33, 41, 7, 30, 45, 11};
        mergeSort(arr, 0, arr.length);
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }

    //[)
    public static void mergeSort(int[] arr, int start, int end) {
        if (end - start <= 1) {
            return;
        }
        int mid = start + (end - start) / 2;

        mergeSort(arr, start, mid);
        mergeSort(arr, mid, end);

        merge(arr, start, mid, end);
    }

    public static void merge(int[] arr, int start, int mid, int end) {
        int[] e = new int[end - start];
        int eIdx = 0;
        int leftIdx = start;
        int rightIdx = mid;
        //归并
        while (leftIdx < mid || rightIdx < end) {
            if (leftIdx == mid) {
                e[eIdx++] = arr[rightIdx++];
            } else if (rightIdx == end) {
                e[eIdx++] = arr[leftIdx++];
            } else if (arr[leftIdx] <= arr[rightIdx]) {
                e[eIdx++] = arr[leftIdx++];
            } else {
                e[eIdx++] = arr[rightIdx++];
            }
        }
        //放回原数组
        for (int i = 0; i < e.length; i++) {
            arr[start + i] = e[i];
        }
    }
}

总结

排序算法时间复杂度(平均)时间复杂度(最坏)时间复杂度(最好)空间复杂度稳定性
插入排序O(n^2)O(n^2)O(n)O(1)稳定
冒泡排序O(n^2)O(n^2)O(n)O(1)稳定
选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
希尔排序O(n^1.3)O(n^2)O(n)O(1)不稳定
堆排序O(n*log n)O(n*log n)O(n*log n)O(1)不稳定
快速排序O(n*log n)O(n^2)O(n*log n)O(log n) ~ O(n)不稳定
归并排序O(n*log n)O(n*log n)O(n*log n)O(n)稳定

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

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

相关文章

【Revit二次开发】模型中存储数据——参数和外部存储(Parameter, Schema and Entity)

模型中存储数据参数读取写入外部存储SchemaEntity快速获取外部存储参数参数 在Revit平台API中&#xff0c;每个图元对象都有参数属性&#xff0c;它是隶属于图元所有属性的集合&#xff0c;在此集合中更改属性值。 每个图元的参数都有一个与之关联的ElementId类型的ID大多数参…

KMP算法

文章目录KMP算法KMP算法 KMP算法要解决的问题就是在字符串&#xff08;也叫主串&#xff09;中的模式&#xff08;pattern&#xff09;定位问题。说简单点就是我们平时常说的关键字搜索。模式串就是关键字&#xff08;接下来称它为P&#xff09;&#xff0c;如果它在一个主串&…

C++图的建立---邻接矩阵-----邻接表

目录 图的表示方式 邻接矩阵 邻接表 图的遍历 深度优先遍历 深度优先遍历算法步骤&#xff1a; 图的广度优先遍历 广度优先遍历算法步骤: 图的邻接矩阵存储来创建图 代码 运行结果&#xff1a; 图的邻接表存储来创建图 如下图&#xff1a; 运行结果&#xff1…

认定能源管理体系的条件

能源管理体系认证申请清单&#xff08;GB/T 23331-2012《能源管理体系 要求》国家标准&#xff09;体系运行时间超过6个月 1、营业执照复印件&#xff1b; 2、组织机构代码证&#xff08;适用时&#xff09;&#xff1b; 3、生产许可证和其他行政许可证明复印件、资质证明等…

保卫城市消费券安全,从这些做起

近日&#xff0c;顶象发布的《城市消费券安全调研报告》&#xff08;以下简称《调研报告》&#xff09;中明确提出&#xff0c;自消费券发放之日起&#xff0c;黑灰产便盯上了这块蛋糕。据不完全统计&#xff0c;190多亿的消费券&#xff0c;消费者只抢到29%。 而在百度键入消…

公众号网课答案在线查搭建

公众号网课答案在线查搭建 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 题库&#xff1a;题库后台&#xff08;点击跳转&#…

操作系统实验三虚拟存储器管理之模拟页面置换算法(FIFOLRU)

文章目录 一、概述 &#xff08;1&#xff09;置换算法 &#xff08;2&#xff09;缺页率与命中率 二、先进先出置换算法&#xff08;FIFO&#xff09; (1)定义 (2)示例 &#xff08;3&#xff09;Belady异常 三、最近最久未使用置换算法&#xff08;LRU&#xff09; &#…

LeetCode每日一题——764. 最大加号标志

LeetCode每日一题系列 题目&#xff1a;764. 最大加号标志 难度&#xff1a;普通 文章目录LeetCode每日一题系列题目示例思路题解题目 在一个 n x n 的矩阵 grid 中&#xff0c;除了在数组 mines 中给出的元素为 0&#xff0c;其他每个元素都为 1。mines[i] [xi, yi]表示 g…

谈谈HTTP协议的方法里,GET和POST的区别?我来教你如何回答~

目录 前言 一、什么是GET、POST&#xff1f; 1.1GET 1.2POST 二、如何轻松回答&#xff1f; 第一步、直接盖棺定论&#xff1a; 第二步、谈细节上的区别&#xff1a; 前言 要想回答好这个问题&#xff0c;咱们先来了解以下什么是GET、POST方法&#xff0c;有哪些细节要注…

阿宇wifi球机如何连接手机

首先下载APP&#xff0c;请见以下三种方式&#xff1a; &#xff08;1&#xff09;至APP Store、各大应用市场搜索 “智U”&#xff0c;下载并安装APP。  &#xff08;2&#xff09;登录ezcloud.uniview.com官网&#xff0c;扫描界面右下方智U APP二维码&#xff0c;下载并…

SpringBoot线上服务假死解决,CPU内存正常

背景 开发小伙伴都知道线上服务挂掉&#xff0c;基本都是因为cpu或者内存不足&#xff0c;出现GC频繁OOM之类的情况。本篇文章区别以上的情况给小伙伴们 带来不一样的服务挂掉。 还记得哔哩哔哩713事故中那场诡计多端的0吗&#xff1f; 对就是这个0&#xff0c;和本次事故没关…

Python基础知识入门(二)

Python基础知识入门&#xff08;一&#xff09; 一、数字类型 Python 数字数据类型用于存储数值。数据类型是不允许改变的&#xff0c;如改变数字数据类型的值&#xff0c;将重新分配内存空间。 1.数字函数 函数 描述 abs(x) 返回数字的绝对值。如abs(-10) 返回 10。 fa…

前端小游戏——推箱子

最近刚刚更新完了HTML&#xff0c;CSS的万字总结&#xff0c;有很多人已经学习完了文章&#xff0c;感觉反馈还不错&#xff0c;今天&#xff0c;用HTML&#xff0c;CSS&#xff0c;JS的知识编写了一个童年经典游戏 - 推箱子&#xff0c;供学习参考。 推荐学习专栏&#xff1a…

EdrawMax Ultimate v12.0 图表和流程图

EDraw Max 是一个多合一的应用程序&#xff0c;用作演示构建器、图表创建者、可视化业务规划师和协作空间&#xff08;用于快速共享图表和模型并接收反馈&#xff09;。 该软件可用于哪些潜在用途&#xff1f; 任何人都可以从 EDraw Max 中受益。它所针对的主题和感兴趣的领域…

【EasyRL学习笔记】第十一章 模仿学习

文章目录一、前言二、行为克隆三、逆强化学习四、第三人称视角模仿学习五、序列生成和聊天机器人六、关键词总结七、习题一、前言 模仿学习 (imitation learning&#xff0c;IL) 讨论的问题是&#xff0c;假设我们连奖励都没有&#xff0c;要怎么进行更新以及让智能体与环境交…

黑马学Docker(二)

目录&#xff1a; &#xff08;1&#xff09;容器命令介绍 &#xff08;2&#xff09; 容器命令案例1 &#xff08;3&#xff09;容器命令案例2 &#xff08;4&#xff09;容器命令练习 &#xff08;5&#xff09;数据卷命令 &#xff08;6&#xff09; 数据卷挂在案例1 …

数字孪生:实现保险行业数字化转型

现如今&#xff0c;数据分析在各个行业都在广泛的使用&#xff0c;保险行业也不例外。在数字化浪潮席卷全球的时代&#xff0c;如何利用数字化技术驱动业务增长&#xff0c;实现数字化转型&#xff0c;是目前保险行业需要思考的问题。 可视化技术能够助力保险机构更好地解决互联…

[hive]维度模型分类:星型模型,雪花模型,星座模型|范式|纬度建模|数仓分层

数仓&#xff08;十八&#xff09;数仓建模以及分层总结(ODS、DIM、DWD、DWS、DWT、ADS层) - 墨天轮 一、维度模型分类:星型模型,雪花模型,星座模型 1、星型模型 星型模型中只有一张事实表&#xff0c;以及0张或多张维度表&#xff0c;事实与纬度表通过主键外键相关联&#…

vue项目 API接口封装

vue项目 API接口封装 01.基础配置创建 分别创建如下文件和文件夹 Object │ .env.development │ .env.production └─src├─api│ index.js│ login.js├─utils│ request.js.env.development 和 .env.production 配置生产环境和开发环境移步&#xf…

Java程序员不得不会的124道面试题(含答案)

1&#xff09;Java 中能创建 volatile 数组吗&#xff1f; 能&#xff0c;Java 中可以创建 volatile 类型数组&#xff0c;不过只是一个指向数组的引用&#xff0c;而不是整个数组。我的意思是&#xff0c;如果改变引用指向的数组&#xff0c;将会受到 volatile 的保护&#x…