Java,合并排序

时间:2012-01-01 21:23:55

标签: java sorting merge

我一直在尝试编写合并排序,而没有创建额外的数组来保存已排序的部分,几个小时后我找不到错误,这导致数组的最后一位按错误的顺序排序。有很多辅助方法,我用于调试,我把它们留在了。

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

    }
}

3 个答案:

答案 0 :(得分: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

我们采取两个有序的块,结果得到一个无序的块。在第for (int i = segment_two_begin; i <= segment_two_end; i++) {行放置一个断点,并试着抓住Sorter2.sortSegments(0,2,3,4)的案例:

  • 42 <= 47,因此我们呼叫insertAt在47
  • 之前移动42
  • 但这意味着73现在在segment_two - 并且相信已到位!

以下是您的错误:您的sortSegments无法正常宣传。

如果你想一下这个方法,你会发现你实际上并不需要嵌套循环:你需要的只是逐步找到必要的元素。因此,从segment_one_beginsegment_two_end的一个周期和第二个列表中当前位置的指针最好:如果第一个列表中的元素低于第二个列表中的一个,则只需跳到新的位置。如果不是,则执行所需的移位 - 并移动指针。

我已经修复了它对我来说效果很好 - 所以它似乎是你实现中唯一的错误。如果你仍然卡住,请描述你的问题,我会尽力帮助。

答案 1 :(得分:0)

是的,发现错误并修复了那种!

http://pastebin.com/UJ3dFfrN

那是nLogn吗?

答案 2 :(得分: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);
    }

}