八大排序-直接插入排序、希尔排序、直接选择排序、冒泡排序、堆排序、快速排序、归并排序、基数排序(上)2

简介: 八大排序-直接插入排序、希尔排序、直接选择排序、冒泡排序、堆排序、快速排序、归并排序、基数排序(上)2

五、复杂度

不稳定,时间复杂度是O(nlogn)~O(n^2),空间复杂度是O(1)

堆排序(Heap Sort)

一、概念

1.1什么是堆

  • 分为大顶堆和小顶堆
  • 符合完全二叉树
  • 父节点大于(或小于)子节点
  • 第一个非叶子节点:n/2-1(向下取整)

二、排序思想

  1. 首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端
  2. 将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1
  3. 将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组

三、图示过程最大值和末尾的最小值交换位置 重复以上操作 四、代码

4.1代码

public class HeapSort {
    public static void heapSort(int[] arr) {
        // 构建初始大根堆
        buildMaxHeap(arr);
        // 从最后一个非叶子节点开始,依次向上调整堆
        for (int i = arr.length - 1; i > 0; i--) {
            swap(arr, 0, i); // 将堆顶元素(最大值)与最后一个元素交换
            maxHeapify(arr, 0, i); // 调整堆
        }
    }
    private static void buildMaxHeap(int[] arr) {
        // 从最后一个非叶子节点开始,依次向上调整堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            maxHeapify(arr, i, arr.length);
        }
    }
    private static void maxHeapify(int[] arr, int i, int heapSize) {
        int left = 2 * i + 1; // 左子节点下标
        int right = 2 * i + 2; // 右子节点下标
        int largest = i; // 最大值下标
        // 找到左、右子节点中的最大值
        if (left < heapSize && arr[left] > arr[largest]) {
            largest = left;
        }
        if (right < heapSize && arr[right] > arr[largest]) {
            largest = right;
        }
        // 如果最大值不是当前节点,交换最大值和当前节点,继续向下调整
        if (largest != i) {
            swap(arr, i, largest);
            maxHeapify(arr, largest, heapSize);
        }
    }
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    public static void main(String[] args) {
        int[] arr = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
        heapSort(arr);
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

4.2运行结果

排序前的数组为:[5, 2, 6, 0, 3, 9, 1, 7, 4, 8]

排序后的数组为:[0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8, 9]

4.3解释

代码中的buildMaxHeap()方法用于构建初始大根堆,maxHeapify()方法用于调整堆,heapSort()方法实现了堆排序算法。main()方法中用一个示例数组进行测试,并输出排序结果

直接选择排序(Selection Sort)

一、概念

  1. 1.选择排序是一种简单直观的排序算法
    2.无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。
  2. 3.唯一的好处可能就是不占用额外的内存空间

二、实现思路

  1. 1.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
  2. 2.再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  3. 3.重复第二步,直到所有元素均排序完毕。

三、图示过程四、代码

4.1代码

//Selection Sort选择排序
public class Selection {
    public static void main(String[] args) {
     int[] arr = {23,34,21,243,67,432,23,34};
        System.out.println(Arrays.toString(selection(arr)));
    }
    //选择排序
    public static int[] selection(int[] arr) {
        int temp = 0; //定义数据交换时的第三方变量
        for (int i = 0; i < arr.length - 1; i++) {
            int min = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[min] > arr[j]) { //如果arr[j]的值小于arr[min]
                    min = j; //保存j的索引
                }
            }
            temp = arr[i];
            arr[i] = arr[min];
            arr[min] = temp;
            System.out.println("第" + (i + 1) + "轮插入" + Arrays.toString(arr));
        }
        return arr;
    }
}

4.2运行结果

排序前的数组为:[23,34,21,243,67,432,23,34]

排序后的数组为:[21,23,23,34,34,67,243,432]

五、代码优化

5.1代码方案一

第一种:使用一个if判断 i == arr.length-2 ,直接去掉最后一轮对比

问题,如果倒数第二轮排序 最后一位元素比倒数第二位元素小,那么去掉最后一轮排序,最终结果是没有排序完成的

//Selection Sort选择排序
public class Selection {
    public static void main(String[] args) {
     int[] arr = {23,34,21,243,67,432,23,34};
        System.out.println(Arrays.toString(selection(arr)));
    }
    //选择排序
    public static int[] selection(int[] arr) {
        int temp = 0; //定义数据交换时的第三方变量
        for (int i = 0; i < arr.length - 1; i++) {
            if( i == arr.length-2){ //如果i=数组的最后两个值
                break;  //退出循环
            }
            int min = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[min] > arr[j]) { //如果arr[j]的值小于arr[min]
                    min = j; //保存j的索引
                }
            }
            temp = arr[i];
            arr[i] = arr[min];
            arr[min] = temp;
            System.out.println("第" + (i + 1) + "轮插入" + Arrays.toString(arr));
        }
        return arr;
    }
}

5.2代码方案二

第二种优化:

if(i != min ) { //判断只有在min=i时才会运行下面的代码

这种优化方法省略了很多不必要的代码运行,并优化最后一轮是否需要对比

//Selection Sort选择排序
public class Selection {
    public static void main(String[] args) {
     int[] arr = {23,34,21,243,67,432,23,34};
        System.out.println(Arrays.toString(selection(arr)));
    }
    //选择排序
    public static int[] selection(int[] arr) {
        int temp = 0; //定义数据交换时的第三方变量
        for (int i = 0; i < arr.length - 1; i++) {
            int min = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[min] > arr[j]) { //如果arr[j]的值小于arr[min]
                    min = j; //保存j的索引
                }
            }
            if(i != min ) { //判断只有在min=i时才会运行下面的代码
                temp = arr[i];
                arr[i] = arr[min];
                arr[min] = temp;
                System.out.println("第" + (i + 1) + "轮插入" + Arrays.toString(arr));
            }
        }
        return arr;
    }
}

六、复杂度

是一种不稳定排序,时间复杂度是O(n^2),空间复杂度是O(1)

结构化:各个排序对比表格

133c4fbe37a144b5f26ba390d6ae28a.pngd85d5157273ab50f21d5f2df5ae61d2.png



相关文章
|
Java API 微服务
【Spring Boot系列】通过OpenAPI规范构建微服务服务接口
【4月更文挑战第5天】通过OpenAPI接口构建Spring Boot服务RestAPI接口
517 0
|
存储 监控 Linux
【Shell 命令集合 系统管理 】⭐⭐⭐Linux 查看当前正在运行的进程信息 ps命令 使用指南
【Shell 命令集合 系统管理 】⭐⭐⭐Linux 查看当前正在运行的进程信息 ps命令 使用指南
438 0
|
人工智能 JSON Java
【极速入门版】编程小白也能轻松上手Comate AI编程插件
【极速入门版】编程小白也能轻松上手Comate AI编程插件
278 0
|
存储 人工智能 算法
图与树的遍历:探索广度优先、深度优先及其他遍历算法的原理与实现
图与树的遍历:探索广度优先、深度优先及其他遍历算法的原理与实现
820 0
|
关系型数据库 MySQL Linux
Linux命令systemctl详解
`systemctl`是Linux系统用于管理systemd服务的核心命令,它与systemd守护进程交互,实现启动、停止、重启服务及查看服务状态等功能。主要参数包括`start`、`stop`、`restart`、`status`、`enable`和`disable`等。例如,启动Apache服务使用`systemctl start httpd.service`,查看服务状态用`systemctl status &lt;service&gt;`。使用时需注意权限,服务名通常以`.service`结尾,但命令中可省略。最佳实践包括利用tab键补全、定期查看服务状态和合理配置服务自启。
|
算法 索引
SFNC —— 采集控制(四)(下)
SFNC —— 采集控制(四)
284 2
|
机器学习/深度学习 自然语言处理 语音技术
FunAudioLLM 技术测评报告
FunAudioLLM 技术测评报告
|
消息中间件 Windows
win10 安装RabbitMQ的步骤--和报错解决
win10 安装RabbitMQ的步骤--和报错解决
415 4
|
设计模式 前端开发
应用软件功能设计和功能列表
应用软件功能设计和功能列表
664 0
|
Web App开发 数据采集 测试技术
如何隐藏Selenium特征实现自动化网页采集
Selenium是一个流行的自动化网页测试工具,可以通过模拟用户在Chrome浏览器中的操作来完成网站的测试。然而,有些网站会检测浏览器是否由Selenium驱动,如果是,就会返回错误的结果或拒绝访问。为了避免这种情况,我们需要隐藏Selenium的特征,让网站认为我们是正常的用户。
1342 0
如何隐藏Selenium特征实现自动化网页采集