【问题标题】:Merge Sort Java合并排序 Java
【发布时间】:2009-11-14 22:39:55
【问题描述】:

我正在尝试创建一个合并排序方法,但它一直给出错误的排序。我在哪里进行更改以使其实际对数组进行排序?代码的哪一部分必须不同?感谢您的时间。

  public static void mergeSort(int[] array, int left,  int lHigh, int right, int rHigh) {  
        int elements = (rHigh - lHigh +1) ;  
        int[] temp = new int[elements];
        int num = left;
      while ((left <= lHigh) && (right <= rHigh)){
       if (a[left] <= array[right]) {
          temp[num] = array[left];
          left++;
        }
        else {
          temp[num] = array[right];
          right++;
        }
       num++;   
      }
     while (left <= right){
        temp[num] = array[left]; // I'm getting an exception here, and is it because of the num???
        left += 1;
        num += 1;  
     }  
     while (right <= rHigh) {
        temp[num] = array[right];
        right += 1;
        num += 1;  
     }  
     for (int i=0; i < elements; i++){
       array[rHigh] = temp[rHigh];
       rHigh -= 1;   
     }

编辑:现在 mergeSort 并没有真正对数字进行排序,有人可以告诉我它具体在哪里吗?特别是当我打印“测试合并排序”部分时。

【问题讨论】:

  • 嗯..你是想让它正确运行还是只编译?!
  • 在merge()中,第一次调用merge应该是从头到中心,而不是从头到尾。
  • 在merge()中,mergeSort的调用应该是mergeSort(newArray, start,center, center+1,end);
  • 对不起,我的错误,但是当我调用 merge() 时,mergeSort 给出了错误的排序,是因为我复制数组的方式吗?
  • 查看我进一步编辑的答案。你肯定走在正确的轨道上,你的 mergeSort() 函数,但是需要完全重写。

标签: java sorting mergesort


【解决方案1】:

首先,我假设这是学术性的,而不是实用性的,因为您没有使用内置的排序功能。话虽如此,这里有一些帮助您朝着正确的方向前进:

通常,可以将合并排序视为两种不同的方法:merge() 函数将两个排序列表合并为一个排序列表,mergeSort() 函数递归地将列表分解为单个元素列表。由于已经对单个元素列表进行了排序,因此您可以将所有列表合并为一个大的排序列表。

这是一些临时的伪代码:

merge(A, B):
  C = empty list

  While A and B are not empty:
    If the first element of A is smaller than the first element of B:
      Remove first element of A.
      Add it to the end of C.
    Otherwise:
      Remove first element of B.
      Add it to the end of C.

  If A or B still contains elements, add them to the end of C.

mergeSort(A):
  if length of A is 1:
    return A

  Split A into two lists, L and R.

  Q = merge(mergeSort(L), mergeSort(R))

  return Q

也许这会帮助你弄清楚你想去哪里。

如果没有,维基百科上总是有MergeSort

附加

为了帮助您,这里有一些在您的代码中内联的 cmets。

  public static void mergeSort(int[] array, int left,  int lHigh, int right, int rHigh) {   
        // what do lHigh and rHigh represent?

        int elements = (rHigh - lHigh +1) ;     
        int[] temp = new int[elements];
        int num = left;

      // what does this while loop do **conceptually**? 
      while ((left <= lHigh) && (right <= rHigh)){
       if (a[left] <= a[right]) {
          // where is 'pos' declared or defined?
          temp[pos] = a[left];
          // where is leftLow declared or defined? Did you mean 'left' instead?
          leftLow ++;
        }
        else {
          temp[num] = a[right];
          right ++;
        }
       num++;   
      }

     // what does this while loop do **conceptually**?
     while (left <= right){
        // At this point, what is the value of 'num'?
        temp[num] = a[left];
        left += 1;
        num += 1;   
     }
     while (right <= rHigh) {
        temp[num] = a[right];
        right += 1;
        num += 1;       
     }
     // Maybe you meant a[i] = temp[i]?
     for (int i=0; i < elements; i++){
       // what happens if rHigh is less than elements at this point? Could
       // rHigh ever become negative? This would be a runtime error if it did
       a[rHigh] = temp[rHigh];
       rHigh -= 1;      
     }

我故意含糊其辞,所以你考虑一下算法。尝试将您自己的 cmets 插入代码中。如果你能写出概念上发生的事情,那么你可能不需要 Stack Overflow :)

我的想法是您没有正确实施。这是因为看起来您只接触了数组的元素一次(或接近一次)。这意味着您有O(N) 的最坏情况,排序通常至少需要O(N * log N),据我所知,合并排序的更简单版本实际上是O(N^2)

更多:

在最简单的归并排序实现中,我希望在 mergeSort() 方法中看到某种recursion。这是因为归并排序通常是递归定义的。有一些方法可以使用 for 和 while 循环迭代地完成此操作,但我绝对不推荐它作为学习工具,除非您以递归方式获得它。

老实说,我建议使用我的伪代码或您可能在 wikipedia 文章中找到的伪代码来实现这一点并从您的代码开始。如果您这样做后仍然无法正常工作,请在此处发布,我们将帮助您解决问题。

干杯!

最后:

  // Precondition: array[left..lHigh] is sorted and array[right...rHigh] is sorted.
  // Postcondition: array[left..rHigh] contains the same elements of the above parts, sorted.
  public static void mergeSort(int[] array, int left,  int lHigh, int right, int rHigh) {   
        // temp[] needs to be as large as the number of elements you're sorting (not half!)
        //int elements = (rHigh - lHigh +1) ;
        int elements = rHigh - left;

        int[] temp = new int[elements];

        // this is your index into the temp array
        int num = left;

        // now you need to create indices into your two lists
        int iL = left;
        int iR = right;

        // Pseudo code... when you code this, make use of iR, iL, and num!
        while( temp is not full ) {
           if( left side is all used up ) {
             copy rest of right side in.
             make sure that at the end of this temp is full so the
               while loop quits.
           }
           else if ( right side is all used up) {
             copy rest of left side in.
             make sure that at the end of this temp is full so the
               while loop quits.
           }
           else if (array[iL] < array[iR]) { ... }
           else if (array[iL] >= array[iR]) { ... }
        }
 }

【讨论】:

  • 如果没有看到您如何调用该方法,我真的无法帮助您。你能发布一些你正在使用的测试用例吗?
  • 不,我的评论是说实现你需要 iL、iR 和 num 的所有伪代码。
  • 啊哈!我现在看到您在代码中尝试执行的操作。第一个 while 循环基本上比较了所有元素,直到用完对,然后用剩余的元素填充 temp 的其余部分。如果您编写了诸如前置条件和后置条件之类的 cmets,它真的会对您(最终我们)有所帮助。 cmets 帮助你弄清楚你在做什么。
  • 我重写了你的代码,因为我很难理解你的方法。您的方法可能有效,但您需要解决一些问题。像循环控制变量。例如,当你有一个可以使用的 for 循环变量时,为什么索引到 temp 和数组 rHigh。
【解决方案2】:
public class MergeSort {
    public static void main(String[] args) {
        int[] arr = {5, 4, 7, 2, 3, 1, 6, 2};

        print(arr);
        new MergeSort().sort(arr, 0, arr.length - 1);
    }

    private void sort(int[] arr, int lo, int hi) {
        if (lo < hi) {
            int mid = (lo + hi) / 2;
            sort(arr, lo, mid);           // recursive call to divide the sub-list
            sort(arr, mid + 1, hi);       // recursive call to divide the sub-list
            merge(arr, lo, mid, hi);      // merge the sorted sub-lists.
            print(arr);
        }
    }

    private void merge(int[] arr, int lo, int mid, int hi) {
        // allocate enough space so that the extra 'sentinel' value
        // can be added. Each of the 'left' and 'right' sub-lists are pre-sorted.
        // This function only merges them into a sorted list.
        int[] left = new int[(mid - lo) + 2];        
        int[] right = new int[hi - mid + 1];         


        // create the left and right sub-list for merging into original list.
        System.arraycopy(arr, lo, left, 0, left.length - 1);
        System.arraycopy(arr, mid + 1, right, 0, left.length - 1);

        // giving a sentinal value to marking the end of the sub-list.
        // Note: The list to be sorted is assumed to contain numbers less than 100.
        left[left.length - 1] = 100;
        right[right.length - 1] = 100;

        int i = 0;
        int j = 0;

        // loop to merge the sorted sequence from the 2 sub-lists(left and right) 
        // into the main list.
        for (; lo <= hi; lo++) {
            if (left[i] <= right[j]) {
                arr[lo] = left[i];
                i++;
            } else {
                arr[lo] = right[j];
                j++;
            }
        }
    }

    // print the array to console.
    private static void print(int[] arr) {
        System.out.println();
        for (int i : arr) {
            System.out.print(i + ", ");
        }
    }
}

【讨论】:

    【解决方案3】:

    这是另一个!

    private static int[] mergeSort(int[] input){
        if (input.length == 1)
            return input;
    
        int length = input.length/2;
        int[] left = new int[length];
        int[] right = new int[input.length - length];
    
        for (int i = 0; i < length; i++)
            left[i] = input[i];
        for (int i = length; i < input.length; i++)
            right[i-length] = input[i];
    
        return merge(mergeSort(left),mergeSort(right));
    }
    
    private static int[] merge(int[] left, int[] right){
        int[] merged = new int[left.length+right.length];
        int lengthLeft = left.length;
        int lengthRight = right.length;
        while (lengthLeft > 0 && lengthRight > 0){
            if (left[left.length - lengthLeft] < right[right.length - lengthRight]){
                merged[merged.length -lengthLeft-lengthRight] = left[left.length - lengthLeft];
                lengthLeft--;
            }else{
                merged[merged.length - lengthLeft-lengthRight] = right[right.length - lengthRight];
                lengthRight--;
            }
        }
        while (lengthLeft > 0){
            merged[merged.length - lengthLeft] = left[left.length-lengthLeft];
            lengthLeft--;
        }
        while (lengthRight > 0){
            merged[merged.length - lengthRight] = right[right.length-lengthRight];
            lengthRight--;
        }
        return merged;
    }
    

    【讨论】:

      【解决方案4】:
      static void mergeSort(int arr[],int p, int r) {
      
         if(p<r) {
              System.out.println("Pass "+k++);
      
              int q = (p+r)/2;
              mergeSort(arr,p,q);
              mergeSort(arr,q+1,r);
              //System.out.println(p+" "+q+" "+r);
              merge(arr,p,q,r);
          }
      
      }
      
      static void merge(int arr[],int p,int q,int r) {
          int temp1[],temp2[];
      
          //lower limit array
          temp1 = new int[q-p+1];
      
          //upper limit array
          temp2 = new int[r-q];
      
          for(int i=0 ; i< (q-p+1); i++){
              temp1[i] = arr[p+i];
          }
      
          for(int j=0; j< (r-q); j++){
              temp2[j] = arr[q+j+1];
          }
      
          int i = 0,j=0;
      
          for(int k=p;k<=r;k++){
      
              // This logic eliminates the so called sentinel card logic mentioned in Coreman
              if(i!= temp1.length
                      && (j==temp2.length || temp1[i] < temp2[j])
                     ) {
                  arr[k] = temp1[i];
                 // System.out.println(temp1[i]);
                  i++;
              }
              else {
                  //System.out.println(temp2[j]);
                  arr[k] = temp2[j];
      
                  j++;
              }
          }
      }
      

      【讨论】:

        【解决方案5】:

        >

        使用 Sentinel 合并排序

        这段代码运行良好。

         public void mergeSort(int a[], int low, int high) {
        
           if (low < high) {
                int mid = (low + high) / 2;
                mergeSort(a, low, mid);
                mergeSort(a, mid + 1, high);
                merge(a, low, mid, high);
        
            }
        }
        
        
        
        public void merge(int a[], int low, int mid, int high) {
            int n1 = mid - low + 1;// length of an array a1
            int n2 = high - mid; // length of an array a2
            int a1[] = new int[n1 + 1];
            int a2[] = new int[n2 + 1];
            int lowRange = low;
            for (int i = 0; i < n1; i++) {
                a1[i] = a[lowRange];
                lowRange++;
            }
            for (int j = 0; j < n2; j++) {
                a2[j] = a[mid + j + 1];
            }
            a1[n1] = Integer.MAX_VALUE; // inserting sentinel at the end of array a1 
            a2[n2] = Integer.MAX_VALUE; // inserting sentinel at the end of array a2
            int i = 0;
            int j = 0;
            int k = low;
            for (k = low; k <= high; k++) {
        
                    if (a1[i] >= a2[j]) {
                        a[k] = a2[j];
                        j++;
                    } else {
                        a[k] = a1[i];
                        i++;
                    }
        
            }
            if (a2.length >= a1.length) {
                for (int ab = k; ab < a2.length; ab++) {
                    a[k] = a2[ab];
                    k++;
                }
            } else if (a1.length >= a2.length) {
                for (int ab = k; ab < a1.length; ab++) {
                    a[k] = a1[ab];
                    k++;
                }
            }
        
        }
        

        【讨论】:

          【解决方案6】:

          这是另一种选择:

          public class MergeSort {
          public static void merge(int[]a,int[] aux, int f, int m, int l) {
          
              for (int k = f; k <= l; k++) {
                  aux[k] = a[k];
              }
          
              int i = f, j = m+1;
              for (int k = f; k <= l; k++) {
                  if(i>m) a[k]=aux[j++];
                  else if (j>l) a[k]=aux[i++];
                  else if(aux[j] > aux[i]) a[k]=aux[j++];
                  else a[k]=aux[i++];
              }       
          }
          public static void sort(int[]a,int[] aux, int f, int l) {
              if (l<=f) return;
              int m = f + (l-f)/2;
              sort(a, aux, f, m);
              sort(a, aux, m+1, l);
              merge(a, aux, f, m, l);
          }
          public static int[] sort(int[]a) {
              int[] aux = new int[a.length];
              sort(a, aux, 0, a.length-1);
              return a;
          }
          

          }

          【讨论】:

            【解决方案7】:

            这是一个简单的Java合并排序算法:

            提示:始终使用int middle = low + (high-low)/2 而不是int middle = (low + high)/2

            public static int[] mergesort(int[] arr) {
                int lowindex = 0;
                int highindex = arr.length-1;
                mergesort(arr, lowindex, highindex);
                return arr;
            }
            
            private static void mergesort(int[] arr, int low, int high) {
                if (low == high) {
                    return;
                } else {
                    int midIndex = low + (high-low)/2;
                    mergesort(arr, low, midIndex);
                    mergesort(arr, midIndex + 1, high);
                    merge(arr, low, midIndex, high);
                }
            }
            private static void merge(int[] arr, int low, int mid, int high) {
                int[] left = new int[mid-low+2];
                for (int i = low; i <= mid; i++) {
                    left[i-low] = arr[i];
                }
                left[mid-low+1] = Integer.MAX_VALUE;
                int[] right = new int[high-mid+1];
                for (int i = mid+1; i <= high; i++) {
                    right[i-mid-1] = arr[i];
                }
                right[high - mid] = Integer.MAX_VALUE;
                int i = 0;
                int j = 0;
                for (int k = low; k <= high; k++) {
                    if (left[i] <= right[j]) {
                        arr[k] = left[i];
                        i++;
                    } else {
                        arr[k] = right[j];
                        j++;
                    }
                }
            }
            

            【讨论】:

              【解决方案8】:
              package com.sortalgo;
              

              导入 java.util.Arrays;

              公共类 MyMSort {

              private static void merge(int[] array, int[] result, int low, int mid, int high) {
                  
                  int k =low, i=low; int j=mid+1;
                  
                  while(i<=mid && j<=high) {
                      
                      if(array[i]<= array[j]) {
                          result[k++]=array[i++];
                      }else {
                          result[k++]=array[j++];
                      }
                  }
                  while(i<=mid) {
                      result[k++]=array[i++];
                  }
                  while(j<=high) {
                      result[k++]=array[j++];
                  }
                  for(i=low;i<=high;i++) {
                      array[i]=result[i];
                  }
              }
              
              private static void mergeSort(int[] array, int[] result, int low, int high) {
                  if(high == low) {
                      return ;
                  }
                  
                  int mid = (low + high)/2;
                  mergeSort(array,result, low, mid );
                  mergeSort(array,result, mid+1, high );
                  
                  merge(array, result, low, mid, high);
              }   
              
              
              
              public static void main(String[] args) {
                  int[] array = {8,4,3,12,25,6,13,10};
                  int[] result = new int[array.length];
                  
                  mergeSort(array, result, 0, array.length-1 );
                  for(int i=0; i<=array.length-1;i++) {
                      System.out.println(array[i]);
                  }
              }
              

              }

              【讨论】:

              猜你喜欢
              • 2011-03-23
              • 2012-11-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多