2009-11-14 2 views
3

Я пытаюсь создать метод сортировки слиянием, но он продолжает давать неправильные сортировки. Где у меня есть изменения, чтобы он действительно сортировал массив? Какая часть кода должна быть другой? Спасибо за ваше время.Merge Сортировка Java

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

EDIT: теперь mergeSort действительно не сортирует цифры, может ли кто-нибудь сказать мне, где именно? особенно когда я печатаю часть «Сортировка слияния».

+0

Умм .. вы пытаетесь, чтобы он работает правильно или просто скомпилировать ?! – notnoop

+0

в merge(), первый вызов слияния должен начинаться с центра, а не от начала до конца. –

+0

в merge(), вызов mergeSort должен быть 'mergeSort (newArray, start, center, center + 1, end);' –

ответ

19

Прежде всего, я предполагаю, что это скорее академический, чем практический, поскольку вы не используете встроенную функцию сортировки. Это, как говорится, поможет вам двигаться в правильном направлении:

Обычно можно рассматривать сортировку слияния как два разных метода: функцию 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 

Может быть, поможет прояснить, где вы хотите пойти.

Если нет, в wikipedia всегда есть MergeSort.

Дополнительная:

Чтобы помочь вам, вот некоторые комментарии встроенные в вашем коде.

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

Я целенаправленно расплывчато, поэтому вы думаете об алгоритме. Попробуйте вставить свои собственные комментарии в код. Если вы можете написать то, что концептуально происходит, вам может не понадобиться переполнение стека :)

Мои мысли здесь в том, что вы не реализуете это правильно. Это потому, что похоже, что вы только касаетесь элементов массива только один раз (или только один раз). Это означает, что у вас есть худший сценарий O(N) Сортировка обычно занимает не менее O(N * log N), и из того, что я знаю, более простые версии сортировки слияния на самом деле - O(N^2).

Подробнее:

В наиболее упрощенной реализации сортировки слиянием, я бы ожидал увидеть какую-то recursion в методе сортировки слиянием(). Это связано с тем, что сортировка слияния обычно определяется рекурсивно. Есть способы сделать это итеративно, используя петли for и while, но я определенно не рекомендую это как инструмент обучения, пока вы не получите его рекурсивно.

Честно говоря, я предлагаю взять либо мой псевдокод, либо псевдокод, который вы можете найти в статье википедии, чтобы реализовать это и начать с вашего кода. Если вы это сделаете, и он работает неправильно, отправьте его здесь, и мы поможем вам разобраться в изломах.

Cheers!

И наконец:

// 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]) { ... } 
     } 
} 
+0

Хе-хе ... это почти код питона. :) –

+0

см. Мои недавние изменения. –

+0

Я действительно не могу помочь вам, не видя, как вы вызываете метод. Можете ли вы опубликовать некоторые тестовые примеры, которые вы используете? –

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 + ", "); 
     } 
    } 
} 
0

Вот еще!

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; 
} 
0
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++; 
     } 
    } 
} 
0

>

Merge Сортировать Использование Стража

This коды отлично работает.

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++; 
     } 
    } 

} 
0

Вот еще одна альтернатива:

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

}

Смежные вопросы