排序-选择排序 O(n^2)

138 阅读1分钟

1. 简述

不太会写,百度百科介绍的已经很详细,可以查看:baike.baidu.com/item/%E9%80… 选择排序的基本思路为:

  1. 从数组 0 ~ n-1 选出最小的值,放到 0 位置
  2. 从数组 1 ~ n-1 选出最小的值,放到 1 位置
  3. ... n. 从数组 n-1 ~ n-1 选出最小的值,放到 1 位置

2. 实现

package com.omg.sort;

import java.util.Arrays;

/**
 * @description: 选择排序
 * 流程:
 *      第一步:0 ~ n-1  找到最小值,在哪,放到 0 位置上
 *      第二步:1 ~ n-1  找到最小值,在哪,放到 1 位置上
 *      第三步:2 ~ n-1  找到最小值,在哪,放到 2 位置上
 *      ...
 *      第n步:n-1 ~ n-1 找到最小值,在哪,放到 n-1 位置
 */
public class Code01_SelectionSort {
    public static void selectionSort(int[] arr){
        if (null == arr || arr.length <= 1){
            return;
        }

        for (int i = 0; i < arr.length; i++){
            int minIndex = i;
            for (int j = i+1; j < arr.length; j++){
                if (arr[j] < arr[minIndex]){
                    minIndex = j;
                }
            }

            if (i != minIndex){
                swap(arr, i, minIndex);
            }
        }
    }

    /** 
     * @description: 交换数组中 i 和 j 位置的元素
     */ 
    public static void swap(int[] arr, int i, int j){
        arr[i] = arr[i]^arr[j];
        arr[j] = arr[i]^arr[j];
        arr[i] = arr[i]^arr[j];
    }

    /** 
     * @description: 对数器,为了验证实现是否正确
     */  
    public static void comparator(int[] arr) {
        Arrays.sort(arr);
    }

    /** 
     * @description: 生成随机数组,用来测试排序,并与对数器比较结果 
     * @param maxSize 数组的最大长度
     * @param maxValue 数组中元素的取值区间 [-maxValu, maxValu]
     */ 
    public static int[] generateRandomArray(int maxSize, int maxValue){
        // Math.random()   [0,1)
        // Math.random() * N  [0,N)
        // (int)(Math.random() * (N+1))  [0, N-1]
        int size = (int)(Math.random()*(maxSize+1));
        int[] arr = new int[size];
        for (int i=0; i<arr.length; i++){
            // 数据内元素第区间为 [-maxValue, maxValue]
            arr[i] = (int)(Math.random()*(maxValue+1)) - (int)(Math.random()*(maxValue+1));
        }
        return arr;
    }

    /** 
     * @description: 数组拷贝,创建一个相同的数组,用于对数器排序比较
     */ 
    public static int[] copyArray(int[] arr){
        if (arr == null) {
            return null;
        }

        int[] res = new int[arr.length];
        for (int i=0; i<arr.length; i++){
            res[i] = arr[i];
        }

        return res;
    }

    /** 
     * @description: 判断两个数组是否相同
     */ 
    public static boolean isEqual(int[] arr1, int[] arr2) {
        if (arr1 == arr2){
            return true;
        }

        if (arr1.length != arr2.length){
            return false;
        }

        if (arr1 != null && arr2 != null){
            for (int i=0; i<arr1.length; i++){
                if (arr1[i] != arr2[i]){
                    return false;
                }
            }
        }

        return true;
    }

    /** 
     * @description: 打印数组,如果排序结果和对数器的结果不一致可以打印出来,方便分析问题
     */ 
    public static void printArray(int[] arr) {
        if (arr == null) {
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }


    public static void main(String[] args) {
        // 测试次数
        int testTime = 50000;
        // 数组最大长度
        int maxSize = 100;
        // 数组内元素取值区间 [-100, 100]
        int maxValue = 100;
        boolean succeed = true;
        for (int i=0; i<testTime; i++){
            int[] arr1 = generateRandomArray(maxSize, maxValue);
            int[] arr2 = copyArray(arr1);
            selectionSort(arr1);
            comparator(arr2);
            // 自己实现的选择排序结果与对数器结果比较,如果不一致 break 跳出循环
            if (!isEqual(arr1, arr2)){
                succeed = false;
                printArray(arr1);
                printArray(arr2);
                break;
            }
        }
        
        System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    }
}

3. 时间复杂度与空间复杂度

3.1 时间复杂度分析

  1. 从数组 0 ~ n-1 选出最小的值,放到 0 位置: 共操作 n 次
  2. 从数组 1 ~ n-1 选出最小的值,放到 1 位置: 共操作 n-1 次
  3. ... n. 从数组 n-1 ~ n-1 选出最小的值,放到 1 位置: 共操作 1 次

通过上面的步骤分析可知,选择排序的时间复杂度为:

n+(n1)+(n2)+...+1=n(n+1)/2n + (n-1) + (n-2) + ... + 1 = n*(n+1)/2

最终可以写为 an2+bn+ca*n^2 + b*n + c 的形式,最终忽略掉常常数项,时间复杂度为 O(n^2)

3.2. 空间复杂度

查看选择排序代码,只有一个变量用来记录最小值的 index。 时间复杂度为 O(1)