Объединить сортировку в Java

Сортировка слиянием в Java

1. Вступление

В этом руководстве мы рассмотримthe Merge Sort algorithm and its implementation in Java.

Сортировка слиянием - один из наиболее эффективных методов сортировки, основанный на парадигме «разделяй и властвуй».

2. Алгоритм

Merge sort is a “divide and conquer” algorithm wherein we first divide the problem into subproblems. Когда решения для подзадач готовы, мы объединяем их вместе, чтобы получить окончательное решение проблемы.

Это один из алгоритмов, который может быть легко реализован с использованием рекурсии, поскольку мы имеем дело с подзадачами, а не с основной проблемой.

Алгоритм может быть описан как следующий двухэтапный процесс:

  • Divide: In this step, we divide the input array into 2 halves, точка поворота является средней точкой массива. Этот шаг выполняется рекурсивно для всех половинных массивов до тех пор, пока не останется больше половинных массивов для деления.

  • Conquer: In this step, we sort and merge the divided arrays снизу вверх и получаем отсортированный массив.

На следующем рисунке показан полный процесс сортировки слиянием для примера массива \ {10, 6, 8, 5, 7, 3, 4}.

Если мы более внимательно посмотрим на диаграмму, то увидим, что массив рекурсивно делится на две половины, пока размер не станет равным 1. Как только размер становится равным 1, процессы слияния вступают в действие и начинают слияние массивов при сортировке:

image

3. Реализация

Для реализацииwe’ll write a mergeSort function which takes in the input array and its length в качестве параметров. Это будет рекурсивная функция, поэтому нам нужны базовые и рекурсивные условия.

Базовое условие проверяет, равна ли длина массива 1, и он просто вернется. В остальных случаях рекурсивный вызов будет выполнен.

For the recursive case, we get the middle index and create two temporary arrays l[] and r[]. Затем функцияmergeSort вызывается рекурсивно для обоих подмассивов:

public static void mergeSort(int[] a, int n) {
    if (n < 2) {
        return;
    }
    int mid = n / 2;
    int[] l = new int[mid];
    int[] r = new int[n - mid];

    for (int i = 0; i < mid; i++) {
        l[i] = a[i];
    }
    for (int i = mid; i < n; i++) {
        r[i - mid] = a[i];
    }
    mergeSort(l, mid);
    mergeSort(r, n - mid);

    merge(a, l, r, mid, n - mid);
}

We then call the merge function which takes in the input and both the sub-arrays and the starting and end indices of both the sub arrays.

Функцияmerge сравнивает элементы обоих подмассивов один за другим и помещает меньший элемент во входной массив.

Когда мы достигаем конца одного из подмассивов, остальные элементы из другого массива копируются во входной массив, тем самым давая нам окончательный отсортированный массив:

public static void merge(
  int[] a, int[] l, int[] r, int left, int right) {

    int i = 0, j = 0, k = 0;
    while (i < left && j < right) {
        if (l[i] <= r[j]) {
            a[k++] = l[i++];
        }
        else {
            a[k++] = r[j++];
        }
    }
    while (i < left) {
        a[k++] = l[i++];
    }
    while (j < right) {
        a[k++] = r[j++];
    }
}

Модульный тест для программы:

@Test
public void positiveTest() {
    int[] actual = { 5, 1, 6, 2, 3, 4 };
    int[] expected = { 1, 2, 3, 4, 5, 6 };
    MergeSort.mergeSort(actual, actual.length);
    assertArrayEquals(expected, actual);
}

4. сложность

Поскольку сортировка слиянием является рекурсивным алгоритмом, временную сложность можно выразить в виде следующего рекурсивного отношения:

T(n) = 2T(n/2) + O(n)

2T(n/2) соответствует времени, необходимому для сортировки подмассивов, иO(n) времени, чтобы объединить весь массив.

При решенииthe time complexity will come to O(nLogn).

Это верно для худшего, среднего и лучшего случая, так как он всегда делит массив на две части, а затем объединяет.

Сложность алгоритма составляетO(n), поскольку мы создаем временные массивы при каждом рекурсивном вызове.

5. Заключение

В этом кратком руководстве мы увидели работу алгоритма сортировки слиянием и его реализацию в Java.

Доступен весь рабочий кодover on GitHub.