java算法:插入排序

基本使用

插入排序是一种简单直观的排序算法,它的工作原理是将待排序的数组分为已排序和未排序两部分,逐步将未排序部分的元素插入到已排序部分中的正确位置,直到整个数组有序。

插入排序的详细步骤:

  • 初始状态:将数组的第一个元素视为已排序部分,其余元素视为未排序部分。
  • 遍历未排序部分:从数组的第二个元素开始,逐个遍历未排序部分的元素。
  • 插入操作:将当前遍历到的元素插入到已排序部分的正确位置。为了找到正确的位置,从当前元素开始,逐个将已排序部分中的元素向后移动,直到找到合适的位置插入当前元素。
  • 重复步骤2和3:重复执行遍历未排序部分和插入操作,直到未排序部分的所有元素都被插入到已排序部分。
public class InsertionSort {
    public static void main(String[] args) {
        int[] arr = {7, 2, 1, 6, 8, 5, 3, 4};
        insertionSort(arr);
        System.out.println("Sorted array: " + Arrays.toString(arr));
    }

    public static void insertionSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; i++) {
            int key = arr[i]; // 当前要插入的元素
            int j = i - 1; // 已排序部分的最后一个元素的索引

            // 将已排序部分中比当前元素大的元素向后移动
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }

            // 插入当前元素到正确的位置
            arr[j + 1] = key;
        }
    }
}

插入排序的时间复杂度为O(n^2),其中n是数组的长度。它是一种稳定的排序算法,并且在小规模数据或部分有序的数据上表现良好。然而,在处理大规模数据时,插入排序的性能可能不如其他更高效的排序算法。

优缺点

优点:

  • 简单易实现: 插入排序算法的实现相对简单,易于理解和编写。
  • 原地排序: 插入排序只需要使用常数级别的额外空间,可以在原地进行排序,不需要额外的辅助空间。
  • 稳定性: 插入排序是一种稳定的排序算法,相等元素的相对顺序在排序后不会改变。

缺点:

  • 较慢的平均和最坏时间复杂度:插入排序的平均时间复杂度为 O ( n 2 ) O(n^2) O(n2),最坏情况下的时间复杂度也是 O ( n 2 ) O(n^2) O(n2),其中n是待排序元素的数量。这使得插入排序在处理大规模数据时效率较低。
  • 对逆序数据的排序效率低:如果待排序的数据已经部分有序或者是逆序的,插入排序的效率会明显降低。当逆序度较高时,需要进行大量的元素移动操作,导致性能下降。
  • 不适用于大规模数据: 由于插入排序的时间复杂度较高,它在处理大规模数据时的性能表现不如其他更高级的排序算法(如快速排序、归并排序等)。
  • 不适用于链式结构: 插入排序需要频繁地访问和移动元素,对于链式结构来说,访问和移动的成本较高,因此不适用于链表等非随机访问结构的排序。

尝试优化

插入排序是一种简单但效率较低的排序算法,但可以通过一些优化策略来提高其性能。

二分查找插入

在传统的插入排序中,为了找到当前元素的正确插入位置,需要逐个比较已排序部分中的元素。然而,我们可以使用二分查找的方法来减少比较的次数。具体步骤如下:

  • 将当前元素与已排序部分的中间元素进行比较。
  • 如果当前元素小于中间元素,则继续在已排序部分的前半部分进行二分查找。
  • 如果当前元素大于等于中间元素,则继续在已排序部分的后半部分进行二分查找。最终找到插入位置后,将已排序部分中插入位置后的元素都向后移动一位,并将当前元素插入到正确位置。

使用二分查找插入可以减少比较的次数,从而提高插入排序的性能。这种优化方法将插入排序的时间复杂度降低到 O ( n l o g n ) O(nlogn) O(nlogn)

public class InsertionSort {
    public static void main(String[] args) {
        int[] arr = {7, 2, 1, 6, 8, 5, 3, 4};
        insertionSort(arr);
        System.out.println("Sorted array: " + Arrays.toString(arr));
    }

    public static void insertionSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; i++) {
            int key = arr[i]; // 当前要插入的元素
            int j = binarySearch(arr, key, 0, i - 1); // 使用二分查找找到插入位置

            // 将已排序部分中插入位置后的元素都向后移动
            System.arraycopy(arr, j, arr, j + 1, i - j);

            // 插入当前元素到正确的位置
            arr[j] = key;
        }
    }

    public static int binarySearch(int[] arr, int key, int start, int end) {
        while (start <= end) {
            int mid = start + (end - start) / 2;
            if (arr[mid] == key) {
                return mid;
            } else if (arr[mid] < key) {
                start = mid + 1;
            } else {
                end = mid - 1;
            }
        }
        return start;
    }
}

减少交换操作

在传统的插入排序中,为了将当前元素插入到正确的位置,需要将较大的元素逐个向后移动,直到找到合适的位置。然而,我们可以通过将较大的元素向右移动一位,并将当前元素直接插入到正确位置来减少交换操作。具体步骤如下:

  • 将当前元素存储在临时变量中。
  • 向右移动较大的元素,直到找到合适的位置。
  • 将当前元素插入到正确的位置。

这种优化方法减少了交换操作的次数,从而提高了插入排序的性能。

public class InsertionSort {
    public static void main(String[] args) {
        int[] arr = {7, 2, 1, 6, 8, 5, 3, 4};
        insertionSort(arr);
        System.out.println("Sorted array: " + Arrays.toString(arr));
    }

    public static void insertionSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; i++) {
            int key = arr[i]; // 当前要插入的元素
            int j = i - 1; // 已排序部分的最后一个元素的索引

            // 将较大的元素向右移动一位
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }

            // 插入当前元素到正确的位置
            arr[j + 1] = key;
        }
    }
}
  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆亦何为

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值