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


排序


选择排序

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

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的图

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值