选择排序

选择排序

选择排序的思想就是从待排数组中将最小的一个元素筛选出来并移动到数组最前端,然后将待排数组的范围缩小(即将已排序的第一个元素排除在外),循环对待排数组进行相同排序处理,直到所有元素都已经排好序
假定初始数组为:{3,5,4,2,1}
选择排序_第1张图片
第一次排序后得到{1,5,4,2,3}
选择排序_第2张图片
第二次排序后得到{1,2,4,5,3}
选择排序_第3张图片
第三次排序后得到{1,2,3,5,4}
选择排序_第4张图片
第四次排序后得到{1,2,3,4,5}
选择排序_第5张图片
第五次排序后得到{1,2,3,4,5}
选择排序_第6张图片
对应的算法代码为:

static void selection(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {        //外层循环
        int index = i;
        for (int j = index + 1; j < arr.length; j++) {//内层循环
            index = arr[j] < arr[index] ? j : index;  //找到最小元素所在的索引位置
        }
        Utils.swap(arr, i, index);                    //交换arr数组中下标为i和index的两个索引的值
    }
}

优化

上述选择排序算法一次遍历只是找出待排数组中最小的一个值,然后插入到数组头位置,优化的思路就是在每次遍历的过程中不止找出待排数组中的最小值放到头位置,同时也找出最大值放到尾位置
对应的算法代码为:

static void selectionEnhanced1(int[] arr) {
    for (int i = 0; i < arr.length / 2; i++) {//外层循环的次数压缩至一半
        int minPos = i, min = minPos, maxPos = arr.length - i - 1, max = maxPos;
        for (int j = min; j <= max; j++) {    //每次遍历都找出剩余元素中最大值和最小值的索引位置
            minPos = arr[j] < arr[minPos] ? j : minPos;
            maxPos = arr[j] > arr[maxPos] ? j : maxPos;
        }
        Utils.swap(arr, min, minPos);         //交换
        Utils.swap(arr, max, maxPos);         //交换
    }
}

再次优化???

经过上述优化后的代码已经可以在一次遍历时将待排数组中的最大值和最小值放置到指定位置,那么在此基础上还可以进行优化吗?其实也是可以的,对代码每次循环所增长的步长进行变化可以减少进入循环体的次数,从而达到优化的目的,以下代码相比较于基础方式,循环体代码的执行次数最高可以降低到原有的四分之一
对应的算法代码为:

static void selectionEnhanced2(int[] arr) {
    for (int i = 0; i < arr.length / 2; i++) {
        int minPos = i, min = minPos, maxPos = arr.length - i - 1, max = maxPos;
        for (int j = min; j <= max; j += 2) {
            minPos = arr[j] < arr[minPos] ? j : minPos;
            maxPos = arr[j] > arr[maxPos] ? j : maxPos;
            if (j + 1 <= max) {
                minPos = arr[j + 1] < arr[minPos] ? j + 1 : minPos;
                maxPos = arr[j + 1] > arr[maxPos] ? j + 1 : maxPos;
            }
        }
        //该代码还有Bug,即在交换的时候需要考虑一些特殊情况的处理,感兴趣的可以自行发掘改正
        Utils.swap(arr, min, minPos);
        Utils.swap(arr, max, maxPos);
    }
}

测试排序结果

通过对数器的方式进行排序结果的验证

//测试代码
public static void main(String[] args) {
    int size = 15;
    //自定义方法:用于获取指定个数和数值范围的数组的方法
    int[] arr1 = Utils.generateRandomArray(size, 100);
    int[] arr2 = new int[size];
    System.arraycopy(arr1, 0, arr2, 0, arr1.length);
    int[] arr3 = new int[size];
    System.arraycopy(arr1, 0, arr3, 0, arr1.length);
    int[] arr4 = new int[size];
    System.arraycopy(arr1, 0, arr4, 0, arr1.length);
    System.out.println("原数组:\t\t\t\t\t" + Arrays.toString(arr1));
    Arrays.sort(arr1);
    System.out.println("系统方法排序后:\t\t\t" + Arrays.toString(arr1));
    selection(arr2);
    System.out.println("基础选择排序排序后:\t\t" + Arrays.toString(arr2));
    selectionEnhanced1(arr3);
    System.out.println("优化版选择排序排序后:\t" + Arrays.toString(arr3));
    selectionEnhanced2(arr4);
    System.out.println("再次优化版选择排序排序后:\t" + Arrays.toString(arr4));
}
原数组:			[47, 48, 50, 75, 30, 84, 16, 49, 2, 31, 22, 90, 21, 33, 14]
系统方法排序后:		[2, 14, 16, 21, 22, 30, 31, 33, 47, 48, 49, 50, 75, 84, 90]
基础选择排序排序后:		[2, 14, 16, 21, 22, 30, 31, 33, 47, 48, 49, 50, 75, 84, 90]
优化版选择排序排序后:	        [2, 14, 16, 21, 22, 30, 31, 33, 47, 48, 49, 50, 75, 84, 90]
再次优化版选择排序排序后:	[2, 14, 16, 21, 22, 30, 31, 33, 47, 48, 49, 50, 75, 84, 90]

如果对你有帮助,点个赞,或者打个赏吧,嘿嘿
整理不易,请尊重博主的劳动成果

你可能感兴趣的:(选择排序)