合并插入排序的详细指南

462 阅读5分钟

在这篇文章中,我将详细讨论合并插入排序的问题。

内容

  • 简介
  • 插入式排序
  • 合并排序
  • 合并算法
  • 它是如何工作的
  • 实施

引言

合并插入排序是合并排序和插入排序的组合,对于较小的n值来说,其最坏情况下的时间复杂度最小。因此,在这篇文章中,我将对插入排序和合并排序做一个简单的描述,然后,我将讨论插入排序和合并排序如何结合起来开发一种排序算法,这种算法具有更好的空间和时间复杂度。

插入式排序

在插入排序中,我们实际上是将给定的数组分割成已排序和未排序的部分。之后,我们将未排序部分的每个元素插入到排序部分的正确位置上。
例如。如果我们想对这个数组进行排序。[5,4,3,2,4]
Screenshot--1076-

时间复杂度。

  • 使用插入式排序算法对数组进行排序的最坏情况下的时间复杂度是O(n^2),其中n是给定数组中元素的总数。

  • 在所有的排序
    算法
    中,插入式排序的最坏情况下的时间复杂度是最高的
    ,但是如果数组已经被排序,它需要的时间是最少的,即它的最佳
    情况下的时间复杂度是O(n)。

空间复杂度:O(1)

合并排序

在合并排序中,我们将给定的数组分成两部分,分别进行排序,然后将这两部分排序的结果合并。
我们将给定的数组分成两个相等的部分,直到只剩下一个元素,即数组不能被进一步分割。

让我们举个例子,用合并排序法对给定数组=[8,3,4,12,5,6]进行排序。

  1. 我们对给定的数组进行这样的划分
    m3-1
  2. 然后,我们将合并排序后的部分
    mergeS

时间复杂度。
合并排序的最坏情况、最好情况和平均情况的时间复杂度是O(N*log(N))。合并排序的最坏情况下的时间复杂度是所有编程算法中最低的。

空间复杂度。O(N)

合并算法

1959年,Ford和Johnson最初描述了合并插入排序。因此,它也被称为福特和约翰逊算法。合并插入排序基本上是插入排序和合并排序的结合,或者我们可以说合并插入排序是在结合了两种排序技术的优点之后形成的结果。

这种排序技术结合了合并(如合并排序)和二进制搜索插入(如插入排序),但是,它能够通过选择要比较的元素来实现更好的最坏情况下的性能,因此,它将最大限度地提高效率,减少算法的时间完整性。

它是如何工作的

现在我将解释合并排序的工作原理。让我们考虑一个大小为N的数组:

  1. 首先,我们将把给定的N个数组元素分成(N/K)组,每组大小为K。
    MISORT1

  2. 现在我们将对每个大小为k的子数组进行排序,就像我们以前在插入排序中做的那样。 下面讨论了对每个子数组进行排序的时间复杂性。

    • 正如前面所讨论的,插入式排序的最佳情况是O(N),
      因为在这种情况下,我们有(N/K)个大小为k的子数组,所以每个子数组的复杂度将是O(k),对于整个数组,它将是
      K*(N/K),即O(N)。

    • 同样,在最坏的情况下,对每个子阵列进行排序的时间复杂度将是O(K^2),对整个阵列来说,它将是(KK)(N/K),即O(N*K)。

  3. 现在,在对每个子数组进行排序后,我们将合并(N/K)排序的子数组,就像我们
    以前在合并排序中做的那样。

    mergeS1

时间复杂度分析

假设我们必须在合并排序中做i次迭代来合并排序的部分:
(2^i) * K = N => (2^i) = N/K => i*(log(2)) = log(N/K) => i = log(N/K)
因此,合并所需时间 = O(N*log(N/K)

什么时候会出现最好的情况
考虑一个已经排序的数组。因此,使用插入排序对所有子数组进行排序的时间复杂度将是O(N),其中N是给定的输入数组的大小。
因此,在最佳情况下组合算法的总时间复杂度是:
最佳情况:N+N*log(N/K)

什么时候会出现最坏情况
正如前面所讨论的,在最坏情况下使用插入排序对所有子数进行排序的时间复杂度将是O(NK*),其中N是给定输入数组的大小。
因此,在最坏情况下组合算法的总时间复杂度是:
最坏情况:NK

*+ N*log(N/K)

空间复杂度:O(1)

实施

public static final int K = 5;
public static void insertionSort(int A[], int p, int q) {
    for (int i = p; i < q; i++) {
        int tempVal = A[i + 1];
        int j = i + 1;
        while (j > p && A[j - 1] > tempVal) {
            A[j] = A[j - 1];
            j--;
        }
        A[j] = tempVal;
    }
    int[] temp = Arrays.copyOfRange(A, p, q +1);
    Arrays.stream(temp).forEach(i -> System.out.print(i + " "));
    System.out.println();
}

public static void merge(int A[], int p, int q, int r) {
    int n1 = q - p + 1;
    int n2 = r - q;
    int[] LA = Arrays.copyOfRange(A, p, q +1);
    int[] RA = Arrays.copyOfRange(A, q+1, r +1);
    int RIDX = 0;
    int LIDX = 0;
    for (int i = p; i < r - p + 1; i++) {
        if (RIDX == n2) {
            A[i] = LA[LIDX];
            LIDX++;
        } else if (LIDX == n1) {
            A[i] = RA[RIDX];
            RIDX++;
        } else if (RA[RIDX] > LA[LIDX]) {
            A[i] = LA[LIDX];
            LIDX++;
        } else {
            A[i] = RA[RIDX];
            RIDX++;
        }
    }
}

public static void sort(int A[], int p, int r) {
    if (r - p > K) {
        int q = (p + r) / 2;
        sort(A, p, q);
        sort(A, q + 1, r);
        merge(A, p, q, r);
    } else {
        insertionSort(A, p, r);
    }
}

public static void main(String string[]) {
    int[] A = { 2, 5, 1, 6, 7, 3, 8, 4, 9 };
    sort(A, 0, A.length - 1);
    Arrays.stream(A).forEach(i -> System.out.print(i + " "));
}

这个组合算法比两个单独的算法都好,因为如果

  • K = 1,上述算法将作为合并排序工作,这在时间复杂度上更好
  • 如果K=N,上述算法将作为插入排序工作,在空间复杂度上更好

通过OpenGenus的这篇文章,你一定对合并插入排序有了完整的了解。