【问题标题】:How can I implement MergeSort with bound inclusive to exclusive?如何实现 MergeSort 绑定包含到独占?
【发布时间】:2020-07-29 03:06:08
【问题描述】:

我正在尝试在 Java 中实现 MergeSort 算法,以便它对来自 A[start..end] 的数组进行排序。我真的很难实现它,以便它不包括在合并中传入的最后一个索引。我正在尝试追踪我的代码,但一直感到困惑。

这是我的代码:

public class MergeSort {

   public static void main(String[] args) {
      int[] list = new int[] { 3, 7, 5, 2, 9 };
      int[] result = mergeSort(list, 0, list.length);  
      System.out.print("[");
      for (int i = 0; i < result.length; i++) {
         System.out.print(" " + result[i]);
      }
      System.out.println("]");
   }

   public static int[] mergeSort(int[] list, int start, int end) {
      if (end - start < 2) {
         return list;
      } else {
         int mid = (start + end) / 2;
         mergeSort(list, start, mid);
         mergeSort(list, mid + 1, end);
         merge(list, start, mid, end);
         return list;
      }
   }

   public static void merge(int[] list, int start, int mid, int end) {
      int[] copy = new int[list.length];
      for (int i = 0; i < list.length; i++) {
         copy[i] = list[i];
      }
      int i = start;
      int k = start;
      int j = mid + 1;
      while (i <= mid && j <= end) {
         if (copy[i] <= copy[j]) {
            list[k] = copy[i];
            i++;
         } else {
            list[k] = copy[j];
            j++;
         }
         k++;
      }
      while (i <= mid) {
         list[k] = copy[i];
         i++;
         k++;
      }
      while (j < end) {
         list[k] = copy[j];
         j++;
         k++;
      } 
   }   
}

【问题讨论】:

  • 您不应该从问题中删除代码,因为它会使答案不一致。该代码有一些错误,我指出并帮助纠正了这些错误。这没有问题,所有程序员都会犯错误,向他人学习是改进的方法。其他读者会阅读您的代码并且会或不会看到问题,无论如何这是一个很好的练习。阅读代码比编写代码困难得多,因此请尝试看看我在答案中提出了哪些更正建议以及我做了哪些其他更改。
  • 编程学校通常不教授排除上限,但它是一种更好的方法,并且使代码更简单、更通用。我希望每个人都能这样教mergesort

标签: java algorithm sorting mergesort


【解决方案1】:

使用包含start 和排除end 定义的切片调用mergesort 确实是一种明智的方法,因为调用序列更简单:merge(array, 0, array.length) 并且它允许空切片,这对于空数组是必需的。

您的mergesort 方法有一个错误:右切片从mid 开始并在end 之前结束,因此调用应该是mergeSort(list, mid, end);

merge方法也有问题:

  • 您不应复制整个list,而应仅复制从startend 的切片(排除)。如果您合并到临时数组中并在合并后将其复制回来,则更简单。使用这种方法,您可以在左侧部分用完时停止合并,因为右侧部分的剩余值已经在正确的位置。
  • 在将运行索引值与使用此方法排除的上限进行比较时,应使用 &lt; 运算符而不是 &lt;=

这是一个更正的版本:

public class MergeSort {

   public static void main(String[] args) {
      int[] list = new int[] { 3, 7, 5, 2, 9 };
      int[] result = mergeSort(list, 0, list.length);  
      System.out.print("[");
      for (int i = 0; i < result.length; i++) {
         System.out.print(" " + result[i]);
      }
      System.out.println(" ]");
   }

   public static int[] mergeSort(int[] list, int start, int end) {
      if (end - start < 2) {
         return list;
      } else {
         // compute the mid point:
         //  the left part spans from start included to mid excluded
         //  the right part spans from mid included to end excluded
         // avoid adding start and end to prevent overflow overflow for very large arrays
         int mid = start + (end - start) / 2;
         mergeSort(list, start, mid);
         mergeSort(list, mid, end);
         merge(list, start, mid, end);
         return list;
      }
   }

   public static void merge(int[] list, int start, int mid, int end) {
      int[] temp = new int[end - start];
      int k = 0;     // index into the temporary array
      int i = start; // index into the left part, stop at mid
      int j = mid;   // index into the right part, stop at end
      // select from left or right slices and store into the temp array
      while (i < mid && j < end) {
         if (list[i] <= list[j]) {
            temp[k++] = list[i++];
         } else {
            temp[k++] = list[j++];
         }
      }
      // copy the remaining elements from the left part
      while (i < mid) {
         temp[k++] = list[i++];
      }
      // copy the sorted elements back to the original list
      for (i = 0; i < k; i++) {
         list[start + i] = temp[i];
      }
   }   
}

【讨论】:

    【解决方案2】:

    拨打mergeSort(list, 0, list.length - 1);

    或者调用一个辅助函数,比如说F。例如,您可以调用F(list, 0, list.length);,而F 唯一会做的就是调用mergeSort(list, 0, list.length - 1);

    这样你就不会再碰mergeSort了。您只需拨打F

    编辑:

    public class MergeSort {
    
       public static void main(String[] args) {
          int[] list = new int[] {3, 7, 5, 2, 9};
          int[] result = mergeSort(list, 0, list.length);  
          System.out.print("[");
          for (int i = 0; i < result.length; i++) {
             System.out.print(" " + result[i]);
          }
          System.out.println("]");
       }
    
       public static int[] mergeSort(int[] list, int start, int end) {
          return F(list, start, end - 1);
       }
    
       public static int[] F(int[] list, int start, int end) {
          if (end - start < 2) {
             return list;
          } else {
             int mid = (start + end) / 2;
             F(list, start, mid);
             F(list, mid + 1, end);
             merge(list, start, mid, end);
             return list;
          }
       }
    
       public static void merge(int[] list, int start, int mid, int end) {
          int[] copy = new int[list.length];
          for (int i = 0; i < list.length; i++) {
          copy[i] = list[i];
          }
          int i = start;
          int k = start;
          int j = mid + 1;
          while (i <= mid && j <= end) {
             if (copy[i] <= copy[j]) {
                list[k] = copy[i];
                i++;
             } else {
                list[k] = copy[j];
                j++;
             }
             k++;
          }
          while (i <= mid) {
             list[k] = copy[i];
             i++;
             k++;
          }
          while (j < end) {
             list[k] = copy[j];
             j++;
             k++;
          } 
       }   
    }
    

    【讨论】:

    • 那就试试我提到的辅助函数方法。您可以查看我编辑的答案以了解更多详细信息。
    • @MahmoodDarwish:您的提议违背了 OP 的目标:srpall 希望将切片定义为包含 start 并排除 end,这不仅有意义,而且允许一个非常优雅的实现,没有任何虚假的 +1 调整。我希望老师们不要再宣传包含/包含的代码,这会适得其反并且容易出错。
    猜你喜欢
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多