【排序】选择排序及优化

我们常用的十大排序算法:选择排序、冒泡排序、插入排序、堆排序、希尔排序 、归并排序、快速排序、桶排序、计数排序、基数排序。

今天实现的是选择排序的算法。

package com.jandmin.demo.leetcode.sort;

import java.util.Random;

/**
 * @description: 排序算法:
 *                 用第一个位置的数依次和后面每一个位置的数比较,把小的拿出来再继续往后比较,
 *                 这样一轮下来就能得到做小值的位置,然后把最小值的位置和第一个位置数字互换;
 *                 接着拿第二个位置的数...
 *
 * @author: JandMin
 **/
public class SortAlgorithm {
    private static int countInner1 = 0;
    private static int countOut1 = 0;
    private static int countInner2 = 0;
    private static int countOut2 = 0;
    private static int countInner3 = 0;
    private static int countOut3 = 0;
    private static int countInner4 = 0;
    private static int countOut4 = 0;

    /**
     * 初始化数组
     * @param len 数组长度
     * @return
     */
    private static int[] initArray(int len){
        if(len < 0){
            return new int[0];
        }
        int[] array = new int[len];
        Random random = new Random(len);
        for(int i=0; i<len; i++){
            array[i] = random.nextInt(len);
        }
//        System.out.println("数组 --> "+JSONObject.toJSONString(array));
        return array;
    }

    public static void main(String[] args) {
        int len = 10000;
        int[] array = initArray(len);
        // 方案1
        int[] array1 = array.clone();
        long start = System.currentTimeMillis();
        selectMin(array1);
//        System.out.print("排序1--> "+ JSONObject.toJSONString(array1));
        System.out.println(" 1耗时:"+(System.currentTimeMillis()-start)+" ms,countInner:"+countInner1+",countOut:"+countOut1);
        // 方案2
        int[] array2 = array.clone();
        start = System.currentTimeMillis();
        selectMinTwo(array2);
//        System.out.print("排序2--> "+JSONObject.toJSONString(array2));
        System.out.println(" 2耗时:"+(System.currentTimeMillis()-start)+" ms,countInner:"+countInner2+",countOut:"+countOut2);
        // 方案3
        int[] array3 = array.clone();
        start = System.currentTimeMillis();
        selectMinAndMax(array3);
//        System.out.print("排序3--> "+JSONObject.toJSONString(array3));
        System.out.println(" 3耗时:"+(System.currentTimeMillis()-start)+" ms,countInner:"+countInner3+",countOut:"+countOut3);
        // 方案4
        int[] array4 = array.clone();
        start = System.currentTimeMillis();
        selectMinAndMaxTwo(array4);
//        System.out.print("排序4--> "+JSONObject.toJSONString(array4));
        System.out.println(" 4耗时:"+(System.currentTimeMillis()-start)+" ms,countInner:"+countInner4+",countOut:"+countOut4);

    }

    /**
     * @Description: 选择排序:遍历数组,找到最小值的位置,把最小的值放到最前面
     * @param array 数组
     * @return: void
     */
    private static void selectMin(int[] array){
        int length = array.length;
        for(int i=0; i<length; i++){
            countOut1++;
            int minPlace = i; // 最小值下标
            for (int j=i+1; j<length; j++){
                countInner1++;
                minPlace = array[j] < array[minPlace] ? j : minPlace;
            }
            exchange(array, i, minPlace);
        }

    }
    /**
     * @Description: 同时比较两个
     * @Date: 2019/7/1
     * @param array 数组
     * @return: void
     */
    private static void selectMinTwo(int[] array){
        int length = array.length;
        for(int i=0; i<length; i++){
            countOut2++;
            int minPlace = i;
            for (int j=i+1; j<length-1; j=j+2){
                countInner2++;
                if(array[j] < array[j+1]){
                    minPlace = getMinIndex(array,j,minPlace);
                } else {
                    minPlace = getMinIndex(array,j+1,minPlace);
                }
            }
            exchange(array, i, minPlace);
        }
    }
    /**
     * @Description: 选择排序:同时获取最小值和最大值的位置,把最小值放前面,最大值放在最后面(countInner:25,countOut:5)
     * @Date: 2019/6/28
     * @param array 数组
     * @return: void
     */
    private static void selectMinAndMax(int[] array) {
        int length = array.length;
        for(int i=0; i<length/2; i++){
            countOut3++;
            int minPlace = i; // 最小值下标
            int maxPlace = length-1-i; // 最大值下标
            if(array[minPlace] > array[maxPlace]){ // 最大值最小值先比较,不然最后数据交叉时会出问题
                exchange(array,minPlace,maxPlace);
            }
            for (int j=i+1; j<length-i; j++){
                countInner3++;
                if(array[j] < array[minPlace]){
                    minPlace = j;
                } else if(array[j] > array[maxPlace]){
                    maxPlace = j;
                }
            }
            exchange(array, i, minPlace);
            exchange(array, maxPlace, length-1-i);
        }
    }

    /**
     * @Description: 寻找最小值和最大值时同时选择两个进行比较,再跟当前最大值和最小值进行比较
     * @Date: 2019/7/1
     * @param array 数组
     * @return: void
     */
    private static void selectMinAndMaxTwo(int[] array){
        int length = array.length;
        for(int i=0; i<length/2; i++){
            countOut4++;
            int minPlace = i; // 最小值下标
            int maxPlace = length-1-i; // 最大值下标
            if(array[minPlace] > array[maxPlace]){ // 最大值最小值先比较,不然最后数据交叉时会出问题
                exchange(array,minPlace,maxPlace);
            }
            for (int j=i+1; j<length-2-i; j=j+2){
                countInner4++;
                if(array[j]<array[j+1]){
                    minPlace = getMinIndex(array,j,minPlace);
                    maxPlace = getMaxIndex(array,j+1,maxPlace);
                } else {
                    minPlace = getMinIndex(array,j+1,minPlace);
                    maxPlace = getMaxIndex(array,j,maxPlace);
                }
            }
            exchange(array, i, minPlace);
            exchange(array, maxPlace, length-1-i);
        }
    }
    /**
     * @Description: 获取两个数中小数的下标
     * @Date: 2019/7/2
     * @param array 数组
     * @param index1 下标1
     * @param index2 下标2
     * @return: int
     */
    private static int getMinIndex(int[] array,int index1,int index2){
        if(array[index1] < array[index2]){
            return index1;
        }
        return index2;
    }
    /**
     * @Description: 获取两个数中大数的下标
     * @Date: 2019/7/2
     * @param array 数组
     * @param index1 下标1
     * @param index2 下标2
     * @return: int
     */
    private static int getMaxIndex(int[] array,int index1,int index2){
        if(array[index1] > array[index2]){
            return index1;
        }
        return index2;
    }

    /**
     * @Description: 数组两个位置上的数互换
     * @Date: 2019/6/28
     * @param array 数组
     * @param i 小的值下标
     * @param j 大的值小标
     * @return: void
     */
    private static void exchange(int[] array, int i, int j) {
        if(i == j){
            return;
        }
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

执行结果:

 1耗时:100 ms,countInner:49995000,countOut:10000
 2耗时:139 ms,countInner:24995000,countOut:10000
 3耗时:49 ms,countInner:25000000,countOut:5000
 4耗时:87 ms,countInner:12497500,countOut:5000

选择排序虽然简单,但也是可以优化的。也许还有更好的优化方案,欢迎留言交流!!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值