2012-01-01 8 views
2

정렬 된 부분을 유지하기위한 추가 배열을 만들지 않고 코드 병합을 시도했습니다. 오류가 발생하여 몇 시간 후에 배열의 마지막 비트가 잘못된 순서로 정렬됩니다 . . 프로그래머 꽤 도우미 메서드, 나는Java, 병합 정렬

public class Sorter2 
{ 

    public static void toString(int [] list) 
    { 
     for(int i = 0; i < list.length; i++) 
     { 
      System.out.print(list[i]); 
      if(!(i + 1 == list.length)) 
      { 
       System.out.print(","); 
      } 
     } 

     System.out.println(""); 
    } 

    public static void toString(int list[], int from, int to) 
    { 
     for(int i = from; i <= to; i++) 
     { 
      System.out.print(list[i]); 
      if(i + 1 <= to) 
      { 
       System.out.print(","); 
      } 
     } 

     System.out.println(""); 
    } 


    public static void insertAt(int [] list, int insert_at, int taken_from) 
    { 
     int to_insert = list[taken_from]; 
     for(int i = taken_from; i >= insert_at; i--) 
     { 
      if(i != insert_at) 
      { 
       list[i] = list[i - 1]; 
      } 
      else 
      { 
       list[i] = to_insert; 
      } 
     } 
    } 

    public static void sortSegments(int [] list ,int segment_one_begin, int segment_one_end, int segment_two_begin, int segment_two_end) 
    { 
     toString(list, segment_one_begin, segment_two_end); 
     int sorted = 0; 
     for(int i = segment_two_begin; i <= segment_two_end; i++) 
     { 
      for(int l = segment_one_begin + sorted; l <= segment_one_end; l++) 
      { 
       if(list[i] <= list[l]) 
       { 
        insertAt(list, l, i); 
        sorted++; 
       } 
      } 
     } 
     toString(list, segment_one_begin, segment_two_end); 
    } 

    public static void mergeSort(int [] list, int segment_begining, int segment_end) 
    { 
     if(segment_end - segment_begining < 1) 
     { 
      return; 
     } 
     else 
     { 
      int midpoint = (segment_end + segment_begining)/2; 

      mergeSort(list, segment_begining, midpoint); 
      mergeSort(list, midpoint + 1, segment_end); 
      sortSegments(list, segment_begining, midpoint, midpoint + 1, segment_end); 

     } 

    } 
    public static void mergeSort(int [] list) 
    { 
     mergeSort(list, 0, list.length - 1); 
    } 

    public static boolean isInOrder(int [] toCheck) 
    { 
     for(int i = 1; i < toCheck.length; i++) 
     { 
      if(toCheck[i] < toCheck[i - 1]) 
      { 
       return false; 
      } 
     } 

     return true; 
    } 

    public static int [] populate(int numOfItems) 
    { 
     int [] toReturn = new int[numOfItems]; 

     for(int i = 0; i < toReturn.length; i++) 
     { 
      toReturn[i] = (int) (Math.random() * 100 + 1); 
     } 

     return toReturn; 
    } 

    public static void main(String [] args) 
    { 
     int [] nums = populate(20); 
     mergeSort(nums); 
     toString(nums); 
     System.out.println(isInOrder(nums)); 

    } 
} 
+0

여기에 병합 정렬 구현을 찾기 : http://www.vogella.de/articles/JavaAlgorithmsMergesort/article.html – Wilmer

+0

이 숙제 경우 등으로 태그를하시기 바랍니다. –

+0

아니 내 숙제가 아니야. – foFox

답변

4

이 테스트가 재현 될 것이다 그래야 당신의 코드를 약간 조정하자 내가 그들을 왼쪽, 디버깅에 사용되는, 우리는 전체 과정을 볼 수 있었다 :

: 당신이 볼 수 있듯이

Sorter2.sortSegments(0,0,1,1) 
0 1 73,47 
0 1 47,73 
Sorter2.sortSegments(0,1,2,2) 
0 2 47,73,48 
0 2 47,48,73 
Sorter2.sortSegments(3,3,4,4) 
3 4 42,64 
3 4 42,64 
Sorter2.sortSegments(0,2,3,4) 
0 4 47,48,73,42,64 
0 4 42,47,48,73,64 
Sorter2.sortSegments(5,5,6,6) 
5 6 12,38 
5 6 12,38 
Sorter2.sortSegments(5,6,7,7) 
5 7 12,38,14 
5 7 12,14,38 
Sorter2.sortSegments(8,8,9,9) 
8 9 18,87 
8 9 18,87 
Sorter2.sortSegments(5,7,8,9) 
5 9 12,14,38,18,87 
5 9 12,14,18,38,87 
Sorter2.sortSegments(0,4,5,9) 
0 9 42,47,48,73,64,12,14,18,38,87 
0 9 12,42,14,18,38,47,48,64,73,87 
Sorter2.sortSegments(10,10,11,11) 
10 11 60,29 
10 11 29,60 
Sorter2.sortSegments(10,11,12,12) 
10 12 29,60,95 
10 12 29,60,95 
Sorter2.sortSegments(13,13,14,14) 
13 14 21,37 
13 14 21,37 
Sorter2.sortSegments(10,12,13,14) 
10 14 29,60,95,21,37 
10 14 21,29,37,60,95 
Sorter2.sortSegments(15,15,16,16) 
15 16 28,66 
15 16 28,66 
Sorter2.sortSegments(15,16,17,17) 
15 17 28,66,73 
15 17 28,66,73 
Sorter2.sortSegments(18,18,19,19) 
18 19 80,69 
18 19 69,80 
Sorter2.sortSegments(15,17,18,19) 
15 19 28,66,73,69,80 
15 19 28,66,69,73,80 
Sorter2.sortSegments(10,14,15,19) 
10 19 21,29,37,60,95,28,66,69,73,80 
10 19 21,28,29,37,60,95,66,69,73,80 
Sorter2.sortSegments(0,9,10,19) 
0 19 12,42,14,18,38,47,48,64,73,87,21,28,29,37,60,95,66,69,73,80 
0 19 12,21,28,29,37,42,14,18,38,47,48,64,73,87,60,95,66,69,73,80 
12,21,28,29,37,42,14,18,38,47,48,64,73,87,60,95,66,69,73,80 
false 

, 첫 번째 문제는 다음 줄에 자체 명단은 다음과 같습니다

import java.util.Random; 

public class Sorter2 { 
    public static final Random RANDOM = new Random(55); 

    public static void toString(int[] list) { 
     System.out.println(Arrays.toString(list)); 
    } 

    public static void toString(int list[], int from, int to) { 
     System.out.print(from + "\t" + to + "\t"); 
     for (int i = from; i <= to; i++) { 
      System.out.print(list[i]); 
      if (i + 1 <= to) { 
       System.out.print(","); 
      } 
     } 

     System.out.println(""); 
    } 


    public static void insertAt(int[] list, int insert_at, int taken_from) { 
     int to_insert = list[taken_from]; 
     for (int i = taken_from; i >= insert_at; i--) { 
      if (i != insert_at) { 
       list[i] = list[i - 1]; 
      } else { 
       list[i] = to_insert; 
      } 
     } 
    } 

    public static void sortSegments(int[] list, int segment_one_begin, int segment_one_end, int segment_two_begin, int segment_two_end) { 
     System.out.println("Sorter2.sortSegments("+segment_one_begin + "," + segment_one_end + "," + segment_two_begin + "," + segment_two_end + ")"); 
     toString(list, segment_one_begin, segment_two_end); 
     int sorted = 0; 
     for (int i = segment_two_begin; i <= segment_two_end; i++) { 
      for (int l = segment_one_begin + sorted; l <= segment_one_end; l++) { 
       if (list[i] <= list[l]) { 
        insertAt(list, l, i); 
        sorted++; 
       } 
      } 
     } 
     toString(list, segment_one_begin, segment_two_end); 
    } 

    public static void mergeSort(int[] list, int segment_begining, int segment_end) { 
     if (segment_end - segment_begining < 1) { 
      return; 
     } 

     int midpoint = (segment_end + segment_begining)/2; 
     mergeSort(list, segment_begining, midpoint); 
     mergeSort(list, midpoint + 1, segment_end); 
     sortSegments(list, segment_begining, midpoint, midpoint + 1, segment_end); 
    } 

    public static void mergeSort(int[] list) { 
     mergeSort(list, 0, list.length - 1); 
    } 

    public static boolean isInOrder(int[] toCheck) { 
     for (int i = 1; i < toCheck.length; i++) { 
      if (toCheck[i] < toCheck[i - 1]) { 
       return false; 
      } 
     } 

     return true; 
    } 

    public static int[] populate(int numOfItems) { 
     int[] toReturn = new int[numOfItems]; 

     for (int i = 0; i < toReturn.length; i++) { 
      toReturn[i] = (int) (nextRandom() * 100 + 1); 
     } 

     return toReturn; 
    } 

    private static double nextRandom() { 
     return RANDOM.nextDouble(); 
    } 

    public static void main(String[] args) { 
     int[] nums = populate(20); 
     mergeSort(nums); 
     toString(nums); 
     System.out.println(isInOrder(nums)); 
    } 
} 

출력은

Sorter2.sortSegments(0,2,3,4) 
0 4 47,48,73,42,64 
0 4 42,47,48,73,64 

우리는 두 개의 정렬 된 청크를 가져 와서 순서가 지정되지 않은 청크를 얻습니다. 라인 for (int i = segment_two_begin; i <= segment_two_end; i++) {에 중단 점을 넣고 Sorter2.sortSegments(0,2,3,4)의 경우 잡으려고 :

  • 42 <= 47를, 그래서 우리는 47
  • 전에 (42)를 이동 insertAt를 호출하지만 73 segment_two에 지금 - 그리고 장소에 믿어 의미 !

여기에 오류가 있습니다. sortSegments은 광고 한대로 작동하지 않습니다.

그 방법에 대해 잠시 생각하면 실제로 중첩 루프가 필요하지 않음을 알 수 있습니다. 필요한 요소를 단계별로 찾는 것이 필요합니다. 따라서 한 사이클을 segment_one_begin에서 segment_two_end으로 옮기고 두 번째 목록의 현재 위치를 가리키는 포인터를 사용하는 것이 좋습니다. 첫 번째 목록의 요소가 두 번째 목록의 요소보다 낮 으면 새 위치로 건너 뛰기 만하면됩니다. 그렇지 않은 경우 필요한 시프트를 수행하고 포인터를 이동합니다.

수정 사항을 작성 했으므로 제대로 작동합니다. 구현시 유일한 오류 인 것 같습니다. 여전히 문제가 있다면 문제를 설명해 주시면 도와 드리겠습니다.

+0

사실, 나는 숫자의 순서를 바꾸고 싶을 때, 나는 숫자를 오른쪽으로 옮긴 다음 삽입하면 실행 시간에 영향을 미치고, 별도의 배열을 가지고 거기에 정렬 된 순서를 저장하는 것과 비교한다. 그런 다음 원래 배열로 바꾸시겠습니까? 너무 많은 시간이나 메모리를 사용하지 않고 코딩하는 더 좋은 방법이 있습니까? – foFox

+0

그것은 실제로 않습니다. 최악의 경우, 목록이 내림차순으로 처음 정렬 될 때, 각 단계는 두 번째 부분에있는 요소만큼 많은 시프트를 포함합니다 (예 :'k'). 교대 전환은'O (k)'를 취합니다. 따라서 마지막 병합만으로도 O (1/4 n^2) - O (n log n)만큼 오래 걸릴 것입니다.In-place O (n log n) 버전은 [Katajainen, Pasanen & Teuhola 1996] (http://en.wikipedia.org/wiki/Merge_sort#CITEREFKatajainenPasanenTeuhola1996)을 확인하십시오. – alf

+0

그래서 더 나은 옵션은 무엇입니까? 도우미 배열? – foFox

0

예, 오류를 발견하고 그 종류를 고쳤습니다!

http://pastebin.com/UJ3dFfrN

는 nLogn인가요?

+0

질문을 편집하고 "답변"을 작성하지 마십시오. 고맙습니다. – alf

+0

죄송합니다, 새로운 걸까요 : P – foFox

0
import java.util.Scanner; 

public class Main { 
    public static int[] t; 

    public static void merge(int[] a, int lo, int mid, int hi) { 
     int i = lo; 
     int j = mid + 1; 
     for (int k = lo; k <= hi; k++) t[k] = a[k]; 
     for (int k = lo; k <= hi; k++) { 
      if (i > mid) a[k] = t[j++]; 
      else if (j > hi) a[k] = t[i++]; 
      else if (t[j] < t[i]) { 
       a[k] = t[j++]; 
      } else a[k] = t[i++]; 
     } 
    } 

    public static void sort(int[] a) { 
     t = new int[a.length]; 
     sort(a, 0, a.length - 1); 
    } 

    private static void sort(int[] a, int lo, int hi) { 
     if (lo >= hi) return; 
     int mid = lo + (hi - lo)/2; 
     sort(a, lo, mid); 
     sort(a, mid + 1, hi); 
     merge(a, lo, mid, hi); 
    } 

    public static void main(String[] args) { 
     Scanner sc = new Scanner(System.in); 
     int n = sc.nextInt(); 
     int[] arr = new int[n]; 
     for (int i = 0; i < n; i++) arr[i] = sc.nextInt(); 
     sort(arr); 
    } 

}