选择排序详解:直接选择排序+堆排序(思路+图解+代码)

文章目录


排序


选择排序

  • 在待排序序列中,找到最小值(大)的下标,和排好序的末尾交换,放到待排序列的开头,直到全部待排序元素排完
    在这里插入图片描述

1.直接选择排序

在这里插入图片描述

方法一

    /**
     * 选择排序
     *
     * @param array
     */
    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[j] < array[minIndex]) {
                    minIndex = j;//只要比minIndex小,放进去
                }
            }//循环走完后,minIndex存的就是当前未排序的最小值

            //将当前i的值和找到的最小值进行交换
            swap(array,i,minIndex);
        }
    }

    public static void swap(int[] array, int i, int j) {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }

1.遍历数组长度,i从0开始

2.每次循环,都由minIndex = i 来记录最小值的下标

3.j 从i+1开始遍历,只要比记录的最小值小,就让minIndex记录。找到未排序中的最小值,进行交换

4.如果遍历完后,未排序中没有比minIndex存的值小,i的值就是最小值,i++;

  • 效率低, 如果较为有序的序列,在交换时会破坏有序性
  • 时间复杂度:O ( N2 )
  • 空间复杂的:O ( 1 )
  • 稳定性:不稳定
方法二
  • 上面的方法,只是先选出最小的值,然后和i的位置交换,

  • 进行优化:在遍历时选出最大值和最小值,和收尾进行交换

在这里插入图片描述

   /**
     * 选择排序---选最大值和最小值
     *
     * @param array
     */
    public static void selectSort2(int[] array) {
        int left = 0;
        int right = array.length - 1;
        while (left < right) {
            int minIndex = left;
            int maxIndex = left;
            //选出最大值和最小值
            for (int i = left + 1; i <= right; i++) {
                if (array[i] > array[maxIndex]) {
                    maxIndex = i;
                }
                if (array[i] < array[minIndex]) {
                    minIndex = i;
                }
            }
            //用最大值和最小值交换首位
            swap(array, left, minIndex);
            //把left和最小值交换
            //如果left恰好就是最大值,就有可能把最大值换到minIndex的位置
            if(left == maxIndex){
                maxIndex = minIndex;//最大值位置不是left了,而是换到了minIndex
            }
            swap(array, right, maxIndex);
            left++;
            right--;
        }
    }

1.在遍历的过程中,选出最大值的下标和最小值的下标

2.将left和最小值进行交换

3.如果left恰好为最大值,left和最小值交换完成后,最大值就在原来最小值的位置上,

4.maxIndex = minIndex,修正最大值的位置

4.将right和最大值进行交换

直接插入排序和直接排序的区别
  • 和插入排序不同的是,插入排序会持续对已排序的数进行比较,把合适的数放在合适的位置
  • 直接选择排序就是不断找到最小的值,依次放在排好序的末尾,不干预排好的序列

2.堆排序

  • 时间复杂度: O( N * log N)
  • 空间复杂的:O (1)
  • 升序:建大堆

  • 降序:建小堆

在这里插入图片描述

将一组数据从小到大排序 ——> 建立大根堆

为什么不用小根堆:小根堆只能保证,根比左右小,不能保证左右孩子的大小顺序,并且要求对数组本身进行排序

  • 大根堆,保证堆顶元素是最大值,最大值跟最后一个元素交换,将最大的放在最后,usedSize–;
  • 向下调整:调整0下标的树,维护大根堆,最大值继续交换到最后一个有效元素的位置
  • 从后往前,从大到小依次排列,保证在原来数组本身进行排序
    /**
     * 堆排序
     * 时间复杂度: N*logN
     * 空间复杂的:o(1)
     *
     * @param array
     */
    public static void heapSort(int[] array) {
        createBigHeap(array);//创建大根堆
        int end = array.length-1;
        while (end>0){
            swap(array,0,end);//堆顶元素和末尾互换
            shiftDown(array,0,end);//维护大根堆
            end--;
        }
    }
    /**
     * 创建大根堆
     *
     * @param array
     */
    public static void createBigHeap(int[] array) {
        //最后一个结点的下标 = array.length - 1
        //它的父亲结点的下标就为array.length - 1 - 1) / 2
        for (int parent = (array.length - 1 - 1) / 2; parent >= 0; parent--) {
            shiftDown(array, parent, array.length);
        }

    }

    /**
     * 向下调整
     *
     * @param array
     * @param parent
     * @param len
     *///向下调整,每棵树从父结点向下走

    public static void shiftDown(int[] array, int parent, int len) {
        int child = parent * 2 + 1;
        while (child < len) {
            //child < len:最起码要有一个左孩子
            if (child + 1 < len && array[child] < array[child + 1]) {
                child++;
            }//child + 1<len:保证一定有右孩子的情况下,和右孩子比较
            //拿到子节点的最大值
            if (array[child] > array[parent]) {
                swap(array, child, parent);
                parent = child;//交换完成后,让parent结点等于等于当前child结点
                child = 2 * parent + 1;
                //重新求子节点的位置,再次进入循环交换
            } else {
                break;
                //比父结点小,结束循环
            }
        }
    }

  • 时间复杂度: O( N * log 2N)
  • 空间复杂的:O (1)
  • 稳定性:不稳定

点击移步博客主页,欢迎光临~

偷cyk的图


http://www.niftyadmin.cn/n/5185753.html

相关文章

milvus数据管理-压缩数据

Milvus 默认支持自动数据压缩。您可以 配置 Milvus 以启用或禁用 压缩 和自动压缩。 如果自动压缩被禁用&#xff0c;您仍然可以手动压缩数据。 1.手动压缩数据 压缩请求是异步处理的&#xff0c;因为它们通常需要花费很长时间。 from pymilvus import Collection collection…

只使用JS怎么给静态页面网站添加站内全局搜索功能?

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 背景 静态页面通常由HTML、CSS 和 JavaScript…

Linux Control Cgroups

无论 Docker 如何进行隔离&#xff0c;无法否认的是我们在当前宿主机中运行的所有容器&#xff0c;它依赖的硬件资源都只是当前机器。 其实启动的每一个容器进程&#xff0c;它本身其实就是当前宿主机的进程之一&#xff0c;那么本质上来说&#xff0c;它也会和宿主机中的其他…

基础课6——开放领域对话系统架构

开放领域对话系统是指针对非特定领域或行业的对话系统&#xff0c;它可以与用户进行自由的对话&#xff0c;不受特定领域或行业的知识和规则的限制。开放领域对话系统需要具备更广泛的语言理解和生成能力&#xff0c;以便与用户进行自然、流畅的对话。 与垂直领域对话系统相比…

在Sprinng Boot中使用Redis充当缓存

关于我们使用EhCache可以适应很多的应用场景了&#xff0c;但是因为EhCache是进程内的缓存框架&#xff0c;在集群模式下&#xff0c;我们在我们的应用服务器或者云服务器之间的缓存都是独立的。故而在不同的服务器之间的进程会存在缓存不一致的情况&#xff0c;就算我们的EhCa…

如何快速搭建Spring Boot接口调试环境并实现公网访问

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…

太原元宇宙3D交互展厅搭建让观众能够与企业进行更加紧密的沟通和交流

元宇宙虚拟展厅是虚拟世界和现实世界的结合。是一个基于互联网的三维虚拟展示空间&#xff0c;具有连接感知和共享的特点。元宇宙与展厅的融合打破了传统展厅对时间和空间的限制&#xff0c;用户可以随时随地参观虚拟展厅。 1、增添了科技元素 与传统展厅不同&#xff0c;元宇宙…

C语言测试题:用冒泡法对输入的10个字符由小到大排序 ,要求数组做为函数参数。

编写一个函数&#xff1a; 用冒泡法对输入的10个字符由小到大排序 &#xff0c;要求数组做为函数参数。 冒泡排序是一种简单的排序算法&#xff0c;它会多次遍历要排序的数列&#xff0c; 每次遍历时&#xff0c;依次比较相邻的两个元素&#xff0c;如果它们的顺序不符合要求…