2012-01-01 5 views
2

ソートされた部分を保持するための追加の配列を作成せずにマージソートをコードしようとしましたが、数時間後にエラーが見つからず、配列の最後のビットが間違った順序でソートされます。 Theresのかなりの数のヘルパーメソッド、私はそれらを左に、デバッグに使用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

テストが再現可能になるようにのは、あなたのコードビットを調整してみましょう、と私たちは、プロセス全体を見ることができました:。

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

あなたが見ることができるように、第一の問題は、次の行で現れる:

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

結果的に2つの順序付けられたチャンクを取得し、順不同のチャンクを取得します。ライン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までの1つのサイクルと、2番目のリストの現在の位置へのポインタを使用したほうがよいでしょう。最初のリストの要素が2番目のリストの要素よりも低い場合は、新しい位置にスキップするだけです。そうでない場合は、必要なシフトを実行してポインタを移動します。

私は修正を加えましたが、それはうまく動作します。つまり、実装上の唯一のエラーだったようです。あなたがまだ立ち往生している場合は、あなたの問題を説明してください。私は助けようとします。

+0

実際には、私は数字を変更する必要があるときに、数字を右にシフトしてから挿入すると、ランタイムに影響します。それを元の配列に置き換えますか?あまりにも多くの時間やメモリを取引することなく、コーディングのより良い方法がありますか? – foFox

+0

それは確かにあります。最悪の場合、リストが最初に降順でソートされるとき、各ステップには、第2の部分、すなわち、「k」の要素の数だけシフトが含まれる。シフトには 'O(k)'が必要なので、最後のマージだけではO(1/4 n^2) - O(n log n)の長さになります。インプレース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); 
    } 

}