#c# #stack-overflow #mergesort
#c# #переполнение стека #сортировка слиянием
Вопрос:
все! Я пытаюсь реализовать алгоритм сортировки слиянием в C #. И у меня есть исключение StackOverflow с моим кодом. Я пытаюсь понять, в чем проблема, и не могу ее решить.
using System;
class MainClass {
static void merge(int[] arr, int leftIndex, int endLeftIndex, int endRightIndex){
// leftArr [leftIndex ... endLeftIndex]
// rightArr [endLeftIndex 1 ... endRightIndex]
int leftArrLength = endLeftIndex - leftIndex 1;
int rightArrLength = endRightIndex - endLeftIndex;
int[] leftArr = new int[leftArrLength], rightArr = new int[rightArrLength];
// Copying the data from the parent Array to the leftArr amp; rightArr
for(int i = 0; i < leftArrLength; i )
leftArr[i] = arr[leftIndex i];
for(int j = 0; j < rightArrLength; j )
rightArr[j] = arr[endLeftIndex j 1];
// the start index of the array that will be merged
int mergedArrIndex = leftIndex;
// set two start pointers for both left and right arrays
int leftIndexMerge = 0, rightIndexMerge = 0;
// the merging operation
while(leftIndexMerge < leftArrLength amp;amp; rightIndexMerge < rightArrLength){
if(leftArr[leftIndexMerge] < rightArr[rightIndexMerge])
arr[mergedArrIndex ] = leftArr[leftIndexMerge ];
else
arr[mergedArrIndex ] = rightArr[rightIndexMerge ];
}
// copying the rest elements
while(leftIndexMerge < leftArrLength)
arr[mergedArrIndex ] = leftArr[leftIndexMerge ];
while(rightIndexMerge < rightArrLength)
arr[mergedArrIndex ] = rightArr[rightIndexMerge ];
}
static void mergeSort(int[] arr, int leftIndex, int endRightIndex){
if(leftIndex < endRightIndex){
// leftArr [leftIndex ... m]
// rightArr [m 1 ... endRightIndex]
int m = leftIndex (endRightIndex - 1) / 2;
mergeSort(arr, leftIndex, m);
mergeSort(arr, m 1, endRightIndex);
merge(arr, leftIndex, m, endRightIndex);
}
}
public static void Main (string[] args) {
int[] arr = {1,2,5,10,1,2,3,4,4};
mergeSort(arr, 0, arr.Length);
foreach(int i in arr) Console.WriteLine(i);
}
}
Просмотрите код в repl.it :https://repl.it/@MohamedMarzouk/MergeSortImplementationInCSharp
Комментарии:
1. похоже, у вас бесконечный рекурсивный вызов в mergeSort, вы уже выполнили его с помощью отладчика?
2. Нет, я изучил и понял алгоритм с веб-сайта geeksforgeeks. смотрите реализацию на c здесь: geeksforgeeks.org/merge-sort
Ответ №1:
У вас было 2 проблемы
Первое, что вызвало ваше переполнение стека
// int m = leftIndex (endRightIndex - 1) / 2;
// should be
int m = leftIndex (endRightIndex - leftIndex) / 2;
Глядя на источник, вы просто приняли l
за 1
и следующее, которое дало бы вам ошибку index out of range
// mergeSort(arr, 0, arr.Length);
// should be
mergeSort(arr, 0, arr.Length-1);
Никаких оправданий нет 🙂
Комментарии:
1. Это демонстрирует причину, по которой вы никогда не должны использовать
l
в качестве имени переменной!2. @MatthewWatson действительно
3. Другая ошибка демонстрирует, почему индекс верхней границы должен быть исключен.
Ответ №2:
В вашем коде есть 2 проблемы:
-
вычисление среднего индекса неверно:
int m = leftIndex (endRightIndex - 1) / 2;
должно бытьint m = leftIndex (endRightIndex - leftIndex) / 2;
-
аргумент, переданный для первоначального вызова из
Main
неверен:mergeSort(arr, 0, arr.Length)
должен бытьmergeSort(arr, 0, arr.Length - 1);
Это показывает, что соглашение о включении начального и конечного граничных индексов подвержено ошибкам. Если endRightIndex
и endLeftIndex
исключены, больше нет необходимости в 1
/ -1
корректировках. Я бы хотел, чтобы учебные пособия перестали преподавать эту бессмыслицу.
Вот упрощенная версия:
using System;
class MainClass {
static void merge(int[] arr, int leftIndex, int rightIndex, int endIndex) {
// leftArr [leftIndex ... endLeftIndex)
// rightArr [endLeftIndex ... endIndex)
int leftArrLength = rightIndex - leftIndex;
int rightArrLength = endIndex - RightIndex;
int[] leftArr = new int[leftArrLength];
int[] rightArr = new int[rightArrLength];
// Copying the data from the parent Array to the leftArr amp; rightArr
for (int i = 0; i < leftArrLength; i )
leftArr[i] = arr[leftIndex i];
for (int j = 0; j < rightArrLength; j )
rightArr[j] = arr[rightIndex j];
// the start index of the array that will be merged
int mergedArrIndex = leftIndex;
// set two start pointers for both left and right arrays
int leftIndexMerge = 0, rightIndexMerge = 0;
// the merging operation
while (leftIndexMerge < leftArrLength amp;amp; rightIndexMerge < rightArrLength) {
if (leftArr[leftIndexMerge] <= rightArr[rightIndexMerge])
arr[mergedArrIndex ] = leftArr[leftIndexMerge ];
else
arr[mergedArrIndex ] = rightArr[rightIndexMerge ];
}
// copying the rest elements
while (leftIndexMerge < leftArrLength)
arr[mergedArrIndex ] = leftArr[leftIndexMerge ];
// This final loop is actually redundant: these elements are already in place
//while (rightIndexMerge < rightArrLength)
// arr[mergedArrIndex ] = rightArr[rightIndexMerge ];
}
static void mergeSort(int[] arr, int leftIndex, int endIndex) {
if (endIndex - leftIndex >= 2) {
// leftArr [leftIndex ... m)
// rightArr [m ... endIndex)
int m = leftIndex (endIndex - leftIndex) / 2;
mergeSort(arr, leftIndex, m);
mergeSort(arr, m, endIndex);
merge(arr, leftIndex, m, endIndex);
}
}
public static void Main(string[] args) {
int[] arr = { 1, 2, 5, 10, 1, 2, 3, 4, 4 };
mergeSort(arr, 0, arr.Length);
foreach (int n in arr)
Console.WriteLine(n);
}
}