【问题标题】:Merge Sort isn't working合并排序不起作用
【发布时间】:2016-08-19 16:54:48
【问题描述】:

我编写了一个程序,您可以在其中使用 3 种不同的排序方法对 ArrayList 进行排序:冒泡、合并和 bogo(或愚蠢的排序)。代码如下:

import java.util.*;
import java.io.*;
import java.lang.*;
import java.lang.IndexOutOfBoundsException;

public class Sorting {

    public static void bubbleSort(ArrayList<Integer> bubble) {
        int temp;
        if (bubble.size() > 1) {
            for (int i = 0; i < bubble.size(); i++) {
                for (int j = 0; j < bubble.size() - i - 1; j++) {
                    if (bubble.get(i).compareTo(bubble.get(i + 1)) > 0) {
                        temp = bubble.get(i);
                        bubble.set(i, bubble.get(i + 1));
                        bubble.set(i + 1, temp);
                    }
                }
            }
        }
    }

    public static ArrayList<Integer> mergeSort(ArrayList<Integer> merge) {
        if (merge.size() == 1) {
            return merge;
        } else {
            int halfway = merge.size() / 2;
            ArrayList<Integer> left = new ArrayList<Integer>(halfway);
            ArrayList<Integer> right = new ArrayList<Integer>(merge.size() - halfway);

            for (int i = 0; i < halfway; i++) {
                left.add(merge.get(i));
            }
            for (int i = halfway; i < merge.size(); i++) {
                right.add(merge.get(i));
            }

            left = mergeSort(left);
            right = mergeSort(right);

            ArrayList<Integer> newMerge = new ArrayList<Integer>(merge.size());

            int index1 = 0;
            int index2 = 0;

            for (int i = 0; i < merge.size(); i++) {
                if (index1 == left.size()) {
                    merge.set(i, right.get(index2));
                    index2++;
                } else if (index2 == right.size()) {
                    merge.set(i, left.get(index1));
                    index1++;
                } else {
                    if (left.get(index1) <= right.get(index2)) {
                        newMerge.set(i, left.get(index1));
                        index1++;
                    } else if (left.get(index1) >= right.get(index2)) {
                        newMerge.set(i, right.get(index2));
                        index2++;
                    }
                }
            }
            return newMerge;
        }
    }

    public static void bogoSort(ArrayList<Integer> bogo) {
        while (!isOrdered(bogo)) {
            Collections.shuffle(bogo);
        }
    }

    public static boolean isOrdered(ArrayList<Integer> order) {
        for (int i = 0; i < order.size(); i++) {
            if (order.get(i) > order.get(i + 1)) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        try {
            Scanner input = new Scanner(new File("random1.txt"));
            ArrayList<Integer> random = new ArrayList<Integer>();
            while (input.hasNextInt()) {
                random.add(input.nextInt());
            }
            input.close();

            System.out.println("Unsorted: " + random);

            long startTime = System.nanoTime();
            bubbleSort(random);
            long endTime = System.nanoTime();
            long duration = ((endTime - startTime) / 1000000);
            System.out.println("Sorted: " + random);
            System.out.println("Bubble sort took: " + duration + " milliseconds to sort.");
            System.out.println();

            long startTime2 = System.nanoTime();
            mergeSort(random);
            long endTime2 = System.nanoTime();
            long duration2 = ((endTime2 - startTime2) / 1000000);
            System.out.println("Sorted: " + random);
            System.out.println("Merge sort took: " + duration2 + " milliseconds to sort.");
            System.out.println();

            long startTime3 = System.nanoTime();
            bogoSort(random);
            long endTime3 = System.nanoTime();
            long duration3 = ((endTime3 - startTime3) / 1000000);
            System.out.println("Sorted: " + random);
            System.out.println("Bogo sort took: " + duration3 + " milliseconds to sort.");
            System.out.println();
        } catch (FileNotFoundException e) {
            System.out.println("File is not found.");
            System.exit(1);
        }
    }
}

当我运行程序时,出现了未排序的 ArrayList 和冒泡排序方法,但我的合并排序方法收到一个错误,指出我在第 38、57 和 102 行有一个 IndexOutOfBoundsException。我正确地执行了算法但我不知道为什么我会收到错误消息。这背后有什么道理吗?

【问题讨论】:

  • 知道哪些行是 38、57 和 102 会有所帮助
  • 38.左=合并排序(左); 57. newMerge.set(i, left.get(index1)); 102. 合并排序(随机);

标签: java eclipse sorting arraylist mergesort


【解决方案1】:

更正的代码

public static ArrayList<Integer> mergeSort(ArrayList<Integer> merge) {
    if (merge.size() == 1) {
        return merge;
    } else {
        int halfway = merge.size() / 2;
        ArrayList<Integer> left = new ArrayList<Integer>(halfway);
        ArrayList<Integer> right = new ArrayList<Integer>(merge.size() - halfway);

        for (int i = 0; i < halfway; i++) {
            left.add(merge.get(i));
        }
        for (int i = halfway; i < merge.size(); i++) {
            right.add(merge.get(i));
        }

        left = mergeSort(left);
        right = mergeSort(right);

        int index1 = 0;
        int index2 = 0;

        // Merge left and right sub-lists into original list
        // See how the newMerge list is no longer needed
        for (int i = 0; i < merge.size(); i++) {
            if (index1 == left.size()) {
                merge.set(i, right.get(index2));
                index2++;
            } else if (index2 == right.size()) {
                merge.set(i, left.get(index1));
                index1++;
            } else {
                if (left.get(index1) <= right.get(index2)) {
                    merge.set(i, left.get(index1)); // We now set the values into merge
                    index1++;
                } else if (left.get(index1) >= right.get(index2)) {
                    merge.set(i, right.get(index2)); // We now set the values into merge
                    index2++;
                }
            }
        }
        return merge; // We now return a reference to merge, not newMerge
    }
}

public static boolean isOrdered(ArrayList<Integer> order) {
    for (int i = 0; i < order.size() - 1; i++) { // order.size() - 1 prevents going out of bounds
        if (order.get(i) > order.get(i + 1)) {
            return false;
        }
    }
    return true;
}

细化

mergeSort() 的问题

当您开始合并左右子列表时会出现问题。请注意,在合并过程中,您在 newMergemerge 列表上调用 set() 方法。这不是你想要的。在“合并”循环中,当newMerge 列表为空或i 大于其大小时,您可以尝试将其设置到列表中。这就是您遇到错误的原因。由于您的其他排序似乎对传入的原始列表进行排序(而不是创建副本、排序和返回副本),我可以假设您的合并排序旨在执行相同的操作。如果是这种情况,实际上根本不需要newMerge 列表,因为我们可以直接写入原始的merge 列表。这种变化可以在上面的代码中看到。

isOrdered() 的问题

这里的小问题。您应该在 i == order.size() - 1 时终止循环,而不是在 i == order.size() 时终止循环。否则,当i == order.size() - 1order.get(i + 1) 将尝试检索列表中不存在的元素(即越界)。

【讨论】:

  • 解释出了什么问题以及如何解决。不要重新发布 OP 的整个原始代码块,只更改一两行。 (可以只在需要更改的地方发布函数。)
  • 我正在编辑和添加解释。我在发表原始帖子时指定了这一点(即“这是更正后的代码。我现在正在添加 cmets...”)。
【解决方案2】:

我正确执行了算法,但我不知道为什么会收到错误消息。

很明显,您没有正确执行算法,否则您不会得到异常。 ;-)

你在打电话:

merge.set(i, right.get(index2));

merge.set(i, left.get(index1));

这是修改原始列表,而不是从mergeSort 返回的新创建的newMerge 列表。调用者希望返回的列表包含与其传递的一样多的元素,但是(因为它从未被修改过)它实际上为零,这导致调用者出现异常。

使用newMerge 作为set 调用的目标,并使用add 而不是尝试设置特定索引。

【讨论】:

    【解决方案3】:

    对于列表,如果索引大于大小,则不能在特定索引处添加或设置元素。检查文档here。您可以将空值添加到您的 List(newMerge) 来解决此问题,或者只是将元素添加到您的 newMerge 列表中。我更喜欢以后。其他IndexOutOfBoundsException 异常与此有关。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-04
      • 2015-02-09
      • 2016-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-05
      相关资源
      最近更新 更多