# 插入排序的优化

# 视频教程

建议快进播放。

说明:本节内容来自《算法(第 4 版)》第 2 章 《排序》之「实验题 2.1.25」(中文版 P168)。

# 插入排序写法二:先暂存再后移

「将一个数字插入一个有序的数组」这一步,可以不使用逐步交换,使用先赋值给「临时变量」,然后「适当的元素」后移,空出一个位置,最后把「临时变量」赋值给这个空位。

其实这种插入方式更像插入排序本来的样子,《算法导论》上的图更形象。

《算法导论》第 2.1 节 插入排序

参考代码 1







 
 













public class Solution {

    public int[] sortArray(int[] nums) {
        int len = nums.length;
        // 循环不变量:将 nums[i] 插入到区间 [0..i) 使之成为有序数组
        for (int i = 1; i < len; i++) {
            // 先暂存这个元素,然后之前元素逐个后移,留出空位
            int temp = nums[i];
            int j = i;
            // 注意边界 j > 0
            while (j > 0 && nums[j - 1] > temp) {
                nums[j] = nums[j - 1];
                j--;
            }
            nums[j] = temp;
        }
        return nums;
    }
}

参考代码 2

public class Solution {

    public int[] sortArray(int[] nums) {
        int len = nums.length;
        for (int i = 1; i < len; i++) {
            int temp = nums[i];
            int j = i;
            for (; j > 0; j--) {
                if (nums[j - 1] > temp) {
                    nums[j] = nums[j - 1];
                } else {
                    break;
                }
            }
            // 此时 nums[j - 1] <= temp
            // nums[j] 的值被赋值到了 nums[j + 1]
            nums[j] = temp;
        }
        return nums;
    }
}

Python 代码:

from sorting.sorting_util import SortingUtil
from sorting.examples import GenerateRandomArrayStrategy
from sorting.examples import GenerateNearlySortedArrayStrategy

from sorting.selecting_sort import SelectionSort


class InsertionSort:

    def __str__(self):
        return "插入排序"

    @SortingUtil.cal_time
    def sort(self, arr):
        """
        插入排序第 1 版:相比选择排序而言,插入排序的内层循环可以提前终止。
        但是这个版本有个缺点,交换次数太多,每一次交换做了 3 次赋值。
        """
        size = len(arr)
        for i in range(1, size):
            for j in range(i, 0, -1):
                # 只要前面的比后面的“严格”大,就要交换它们的位置
                if arr[j - 1] > arr[j]:
                    arr[j], arr[j - 1] = arr[j - 1], arr[j]
                else:
                    break


class InsertionSortOptimizer:

    def __str__(self):
        return "插入排序(优化)"

    @SortingUtil.cal_time
    def sort(self, arr):
        size = len(arr)
        for i in range(1, size):
            # 每一轮先让这个元素去别的地方休息一下
            temp = arr[i]
            # 从 i 的前一个元素开始看
            j = i
            while j > 0 and arr[j - 1] > temp:
                arr[j] = arr[j - 1]
                j -= 1
            # 因为已经看到索引 j 的值小于等于 temp 了
            # 因此空出来的位置是 j,要把 temp 放在这里
            arr[j] = temp


if __name__ == '__main__':
    # 测试插入排序算法的正确性
    # SortingUtil.test_sorting_algorithm(InsertionSort(), GenerateRandomArrayStrategy(5000))

    # 比较插入排序算法与选择排序
    # SortingUtil.compare_sorting_algorithms(GenerateRandomArrayStrategy(5000),
    #                                        SelectionSort(),
    #                                        InsertionSort())

    # 验证插入排序算法对于几乎有序的数组,越有序越好
    SortingUtil.test_sorting_algorithm(InsertionSortOptimizer(), GenerateRandomArrayStrategy(5000))

    SortingUtil.compare_sorting_algorithms(GenerateRandomArrayStrategy(5000),
                                           SelectionSort(),
                                           InsertionSort(),
                                           InsertionSortOptimizer())

    SortingUtil.compare_sorting_algorithms(GenerateNearlySortedArrayStrategy(5000),
                                           SelectionSort(),
                                           InsertionSort(),
                                           InsertionSortOptimizer())

注意:编码的时候如果不小心,可能会把数组的值修改,建议多调试。

# 参考资料


作者:liweiwei1419 链接:https://suanfa8.com/basic-sorting-algorithm/insertion/optimization 来源:算法吧 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Last Updated: 11/18/2024, 11:23:03 PM