C# 中的合并排序实现 - StackOverflow 异常

Merge Sort Implementation in C# - StackOverflow Exception

大家好! 我正在尝试在 C# 中实现合并排序算法。我的代码有一个 Whosebug 异常。 我想弄清楚问题出在哪里,但我无法解决。

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 & 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 && 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

您有 2 个问题

第一个导致你的堆栈溢出

// int m = leftIndex + (endRightIndex - 1) / 2;
// should be
int m = leftIndex + (endRightIndex - leftIndex) / 2;

查看源代码,您只是将 l 误认为是 1

以及以下会给您索引超出范围的错误

// mergeSort(arr, 0, arr.Length);
// should be
mergeSort(arr, 0, arr.Length-1);

没有任何借口:)

您的代码中有 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);
    

这表明包含开始和结束边界索引的约定很容易出错。如果 endRightIndexendLeftIndex 被排除,则不再需要 +1 / -1 调整。我希望教程停止教授这个 non-sense.

这是一个简化版本:

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 & 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 && 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);
  }
}