【算法】直接插入排序

文章目录

  • 概念
  • 实现过程
    • 时间复杂度和空间复杂度
    • 代码示例
  • 总结

概念

直接插入排序(Insertion Sort)是一种简单直观的排序算法,它的基本思想是通过构建有序的子序列,逐步将无序的元素插入到有序序列中,最终实现整体的排序。

具体来说,直接插入排序的过程如下:

将待排序的序列看作一个有序序列和一个无序序列。初始时有序序列只包含第一个元素,无序序列包含剩下的元素。
逐个取出无序序列中的元素,并将它与有序序列中的元素逐个比较。
找到合适的位置后,将待插入的元素插入到有序序列中,同时将该位置后面的元素依次后移一位。
继续处理下一个无序元素,直到所有的元素都插入完成。
这样,经过多轮的比较和插入操作,整个序列就会逐渐变得有序,最终完成排序。

直接插入排序算法的优点是实现简单,思路清晰,对于小规模的数据集排序效果较好。然而,由于它的时间复杂度为O(n^2),在处理大规模数据时可能不够高效,因此在实际应用中需要综合考虑其他排序算法。

实现过程

假设前面 n-1(其中 n>=2)个数已经是排好顺序的,现将第 n 个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。
按照此法对所有元素进行插入,直到整个序列排为有序的过程,称为插入排序。
从小到大的插入排序整个过程如图示:
第一轮: 从第二位置的 6 开始比较,比前面 7 小,交换位置。
【算法】直接插入排序_第1张图片

第二轮: 第三位置的 9 比前一位置的 7 大,无需交换位置
在这里插入图片描述
第三轮: 第四位置的 3 比前一位置的 9 小交换位置,依次往前比较。
【算法】直接插入排序_第2张图片
第四轮: 第五位置的 1 比前一位置的 9 小,交换位置,再依次往前比较。
【算法】直接插入排序_第3张图片

时间复杂度和空间复杂度

时间复杂度分析:

在最好情况下,即待排序序列已经有序的情况下,直接插入排序的时间复杂度是最低的,为O(n)。因为每个元素只需与前一个元素进行比较一次,无需进行元素的后移操作。
在最坏情况下,即待排序序列逆序的情况下,直接插入排序的时间复杂度是最高的,为O(n^2)。因为每个元素都需要与有序序列中的所有元素进行比较,并可能进行大量的元素后移操作。
平均情况下,直接插入排序的时间复杂度同样为O(n^2)。虽然有部分元素在比较时可能会提前找到合适的位置,减少了后移操作的次数,但整体来说,平均情况仍需进行大量的比较和后移操作。
空间复杂度分析:

直接插入排序的空间复杂度是O(1),即算法所需的额外存储空间是固定的,不随待排序序列规模的增长而增加。只需要使用常数级别的额外空间来保存一些临时变量。
稳定性:

直接插入排序是一种稳定的排序算法。当两个相等的元素进行比较时,如果当前元素小于等于前一个元素,则它们的相对顺序不会改变,仅在有必要时进行元素的后移操作。
优缺点:

优点:直接插入排序算法实现简单,适用于小规模数据或部分有序的数据集。对于部分有序的序列,直接插入排序的效率较高,比如对近乎有序的数据进行排序会非常迅速。
缺点:直接插入排序的时间复杂度较高,特别是在处理大规模数据时。对于逆序或近似逆序的数据,算法的性能退化明显,排序时间会很长。
需要注意的是,直接插入排序可以进行原地排序,即在原始数组上进行排序,不需要额外的存储空间。这是因为算法只涉及元素的比较和后移操作,不需要创建新的数组或链表。

代码示例

public class InsertionSort {
    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 = j - 1;
            }

            arr[j + 1] = key;
        }
    }

    public static void main(String[] args) {
        int[] arr = {5, 2, 8, 12, 3};
        System.out.println("原始数组: ");
        for (int num : arr) {
            System.out.print(num + " ");
        }

        insertionSort(arr);

        System.out.println("\n排序后的数组: ");
        for (int num : arr) {
            System.out.print(num + " ");
        }
    }
}

以上代码定义了一个名为InsertionSort的类,其中包含了一个名为insertionSort的静态方法用于执行直接插入排序。在main方法中,我们创建了一个整型数组arr作为示例输入,并调用insertionSort方法对其进行排序。最终,我们输出排序后的结果。

这段代码中,通过遍历待排序数组,从第二个元素开始逐个将元素插入到已经排好序的子数组中的合适位置,以实现直接插入排序。在插入过程中,对于比当前元素大的元素,我们将其后移一位,直到找到合适的插入位置,然后将当前元素插入该位置。最终,整个数组将按升序排序。

总结

直接插入排序(Insertion Sort)是一种简单直观的排序算法,它的基本思想是将待排序的序列分为已排序和未排序两部分,每次从未排序部分选择一个元素,插入到已排序部分的合适位置,直到所有元素都被插入完毕。以下是直接插入排序的几个要点总结:

实现思路:将待排序序列分为已排序部分和未排序部分。初始时将第一个元素视为已排序部分,剩下的元素视为未排序部分。然后逐个从未排序部分选择元素,通过比较找到插入位置并将其插入到已排序部分,依次重复这个过程直至整个序列有序。

时间复杂度:直接插入排序的最好情况时间复杂度为O(n),最坏情况和平均情况时间复杂度都为O(n^2)。在最好情况下,序列已经有序,只需要进行一次比较即可确定插入位置,所以时间复杂度最低。而在最坏情况下,序列逆序,每个元素都需要与有序序列中的所有元素比较,并可能进行大量的后移操作,导致时间复杂度最高。

空间复杂度:直接插入排序的空间复杂度为O(1),即算法所需的额外存储空间是固定的,不随待排序序列规模的增长而增加。只需要使用常数级别的额外空间来保存一些临时变量。

稳定性:直接插入排序是一种稳定的排序算法。当两个相等的元素进行比较时,如果当前元素小于等于前一个元素,则它们的相对顺序不会改变,仅在有必要时进行元素的后移操作。

优缺点:直接插入排序的优点是实现简单,适用于小规模数据或部分有序的数据集。对于部分有序的序列,直接插入排序的效率较高。然而,直接插入排序的缺点是时间复杂度较高,特别是在处理大规模数据时。对于逆序或近似逆序的数据,算法的性能退化明显,排序时间会很长。

总之,直接插入排序是一种简单但效率略低的排序算法,适用于小规模或部分有序的数据集。它的实现思路清晰,容易理解和实现,同时具备稳定性。然而,在处理大规模数据时,更高效的排序算法如快速排序、归并排序等往往更合适。

你可能感兴趣的:(算法,java,数据结构)