Java — сортировка слиянием с использованием рекурсии

#java #mergesort

#java #сортировка слиянием

Вопрос:

Я просматривал приведенный ниже пример программы и пытался понять, как работает приведенная ниже рекурсия, я не мог понять, как сортируются левые и правые элементы массива, и, наконец, слияние двух подмассивов, как показано ниже. Любое наглядное объяснение приведенного ниже метода было бы очень полезным, поскольку я пытаюсь понять приведенный ниже рекурсивный код.

  public static int[] mergeSort(int[] arrayToSort) {

    // BASE CASE: arrays with fewer than 2 elements are sorted
    if (arrayToSort.length < 2) {
        return arrayToSort;
    }

    // STEP 1: divide the array in half
    // we use integer division, so we'll never get a "half index"
    int midIndex = arrayToSort.length / 2;

    int[] left  = Arrays.copyOfRange(arrayToSort, 0, midIndex);
    int[] right = Arrays.copyOfRange(arrayToSort, midIndex, arrayToSort.length);

    // STEP 2: sort each half
    int[] sortedLeft  = mergeSort(left);
    int[] sortedRight = mergeSort(right);

    // STEP 3: merge the sorted halves
    int[] sortedArray = new int[arrayToSort.length];

    int currentLeftIndex  = 0;
    int currentRightIndex = 0;

    for (int currentSortedIndex = 0; currentSortedIndex < arrayToSort.length;
            currentSortedIndex  ) {

        // sortedLeft's first element comes next
        // if it's less than sortedRight's first
        // element or if sortedRight is exhausted
        if (currentLeftIndex < sortedLeft.length
                amp;amp; (currentRightIndex >= sortedRight.length
                || sortedLeft[currentLeftIndex] < sortedRight[currentRightIndex])) {
            sortedArray[currentSortedIndex] = sortedLeft[currentLeftIndex];
            currentLeftIndex  ;
        } else {
            sortedArray[currentSortedIndex] = sortedRight[currentRightIndex];
            currentRightIndex  ;
        }
    }

    return sortedArray;
}
 

Ответ №1:

Сортировка выполняется в цикле слияния:

  • если массив очень маленький (0 или 1 элемент), mergeSort() возвращает его немедленно.
  • в противном случае он разбивает массив на 2 подмассива примерно одинакового размера, left и right , которые сортируются путем рекурсивного вызова одного и того же метода:
       // STEP 2: sort each half
      int[] sortedLeft  = mergeSort(left);
      int[] sortedRight = mergeSort(right);
     
  • на последнем шаге выполняется итерация по отсортированным половинкам для создания нового отсортированного массива.

Рекурсивные вызовы завершаются, потому что они выполняются только с подмассивами, строго меньшими, чем массив аргументов.

Комментарии:

1. Возможно, было бы проще объяснить, что фактическое слияние не происходит до тех пор, пока вложенное рекурсивное разделение не приведет к двум подмассивам размером по 1 элементу каждый, после чего эти два подмассива объединяются для создания отсортированного подмассива с 2 элементами. Затем разделение и слияние выполняются по цепочке вызовов, сначала глубина, сначала слева.

2. @chqrlie: Спасибо. Я мог понять, что вы объяснили, поскольку то же самое было объяснено в терминах комментария в запросе. Чего я не понимаю, так это того, что рекурсивный вызов, как сортируются 2 подмассива и как два отсортированных подмассива окончательно объединяются с использованием рекурсии. Я попытался понять на примере: arrayToSort имеет 11 элементов, скажем {4,1,-2, 0, 4, 6, 7, 2, 5, 3, 8}. left имеет 5, а right — 6 элементов, скажем, — left : {4,1,-2, 0, 4} иправильно : {6, 7, 2, 5, 3, 8}.. Как они сортируются по отдельности и объединяются. Спасибо.