经典排序算法之二:选择排序

一、选择排序的思想及优化思路(升序为例)

思想:假设给定一个大小为n的数组,从中选出最大的值(记录下标)与下标n - i的值进行交换(i∈[1, n - 1],i为循环次数),即遍历一次交换一次,每次遍历确定一个最大值。
优化思路:使用一种快速查找最值的方法可降低选择排序的时间复杂度,例如使用堆这种数据结构,可在O(logn)的情况下找到最值

二、代码实现

普通代码,cmp()功能为array[maxIndex] - array[begin],swap()功能为交换两个下标所在值。

for (int end = array.length - 1; end > 0 ; end--) {
            int maxIndex = 0;
            for (int begin = 1; begin <=end ; begin++) {
                //=则为稳定排序
                if (cmp(maxIndex, begin) <= 0){
                    maxIndex = begin;
                }
            }
            swap(maxIndex, end);
        }

优化思路代码

int heapSize;

    @Override
    protected void sort() {
        heapSize = array.length;
        //原地建堆
        for (int i = (heapSize >> 1) - 1; i >= 0; i--) {
            siftDown(i);
        }
        while (heapSize > 1) {
            swap(0, --heapSize);
            siftDown(0);
        }
    }

    private void siftDown(int index) {
        E parent = array[index];
        //第一个叶子节点下标即非叶子节点个数
        int half = heapSize >> 1;
        while (index < half) {
            //默认左边
            int childIndex = (index << 1) + 1;
            E child = array[childIndex];
            int rightIndex = childIndex + 1;
            //right
            if (rightIndex < heapSize && cmpOfValue((Integer) array[childIndex], (Integer) array[rightIndex]) < 0) {
                childIndex = rightIndex;
                child = array[rightIndex];
            }
            //拿到字节点最大值放入child后与父节点比较,若子节点大则覆盖父节点,且将下标移动至原最大子节点处
            if (cmpOfValue((Integer) parent, (Integer) child) < 0) {
                array[index] = child;
                index = childIndex;
            } else break;
        }
        array[index] = parent;
    }

三、复杂度分析

普通代码循环执行次数(n-1)*(n-1)即O(n²),一次确定一个最大值,不存在提前退出的情况,最坏与最好的情况一致。
优化代码后使用堆这种数据结构,
步骤①原地建堆,复杂度O(logn)
②进行遍历(复杂度O(n)),将堆顶元素(最大值),与末尾元素交换,进行下滤(保证堆性质,复杂度O(logn))同时减少堆可访问容量,
故复杂度为O(nlogn)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值