【问题标题】:Java Merge Sorting Algorithm Error - Not SortingJava合并排序算法错误-未排序
【发布时间】:2014-03-13 07:51:55
【问题描述】:

我不明白为什么我的使用 ArrayLists 的合并排序程序的算法不起作用...如果男生和女生能帮我弄清楚那将是惊人的!打印所需的格式需要在每个数字上加上标签,并每 20 个数字放在一个新行上。我的程序也仅限于标准 Java 包。示例输入和输出可以在here 找到。这是我的代码:

import java.io.*;
import java.util.*;

public class MergeSort {
public static void main(String[] args) throws IOException{
    Scanner in  = new Scanner(System.in);
    Random r = new Random();
    int size, largestInt, holder;

    System.out.println("How many integers would you like me to create?");
    size = in.nextInt();
    ArrayList<Integer>list = new ArrayList<Integer>(size);
    System.out.println("What would the largest integer be?");
    largestInt = in.nextInt();

    for(int i = 0; i < size; i++){
        holder = r.nextInt(largestInt + 1);
        list.add(holder);
    }
    mergeSort(list);

    for (int j = 0; j < list.size(); j++) {
        if(j == 19 || j == 39 || j == 59 || j == 79 || j == 99 || j == 119 || j == 139 || j == 159 || j == 179 || j == 199){
            System.out.print(list.get(j));
            System.out.println();
        }
        else{
            System.out.print(list.get(j) + "\t");
        }
    }
}

static void mergeSort(ArrayList<Integer> list) {
    if (list.size() > 1) {
        int q = list.size()/2;
        ArrayList<Integer> leftList = new ArrayList<Integer>();
        for(int i = 0; i >0 && i <= q; i++){
            leftList.add(list.get(i));
        }
        ArrayList<Integer> rightList = new ArrayList<Integer>();
        for(int j = 0; j > q && j < list.size(); j++){
            rightList.add(list.get(j));
        }

        mergeSort(leftList);
        mergeSort(rightList);
        merge(list,leftList,rightList);
    }
}

static void merge(ArrayList<Integer> a, ArrayList<Integer> l, ArrayList<Integer> r) {
    int totElem = l.size() + r.size();
    int i,li,ri;
    i = li = ri = 0;
    while ( i < totElem) {
        if ((li < l.size()) && (ri<r.size())) {
            if (l.get(li) < r.get(ri)) {
                a.set(i, l.get(li));
                i++;
                li++;
            }
            else {
                a.set(i, r.get(ri));
                i++;
                ri++;
            }
        }
        else {
            if (li >= l.size()) {
                while (ri < r.size()) {
                    a.set(i, r.get(ri));
                    i++;
                    ri++;
                }
            }
            if (ri >= r.size()) {
                while (li < l.size()) {
                    a.set(i, l.get(li));
                    li++;
                    i++;
                }
            }
        }
    }
}

提前致谢!

【问题讨论】:

  • 以什么方式坏掉了?向我们展示一些示例输出。
  • @chm052 需要从最小值到最大值的顺序打印出来,并且必须使用归并排序算法进行排序(即1,2,3,4,6,19,67,89)
  • 当前打印出什么? 向我们展示一些示例输出以及相应的输入。
  • @chm052 这是输入和输出的链接。如您所见,它没有正确排序:i62.tinypic.com/nvqt6a.png
  • 您的for 循环初始化步骤和mergeSort 中的测试不符合您的要求。不过,我怀疑这是你唯一的错误。

标签: java algorithm sorting arraylist


【解决方案1】:

您的问题尚不清楚,但由于您需要实现合并排序算法,我认为这是对您不利的部分。一旦你有一个正确排序的列表,格式打印应该很容易通过反复试验。

我认为您的解决方案过于复杂化了问题。 MergeSort 是目前最简单的排序算法之一,但您的代码远非简单。

想想归并排序是如何工作的——它本质上是递归的,因为它是一种分而治之的方法。它通过将一个大而复杂的问题拆分为简单的小问题来解决它,并且基本上只是合并所有这些问题的结果 - 你的 MergeSort 算法只需要包含这个。

如果我们把它写出来,您需要执行以下步骤:

(1) 检查列表是否只包含一个元素 - 那么它已经排序了

(2) 将输入拆分为大小相等的列表并在继续之前对它们进行排序(递归步骤)

(3) 合并两个排序列表,返回一个排序列表。

我看到您对合并部分有一个复杂的方法,并对拆分部分使用基本迭代。 Java List(例如ArrayList 的超类)提供了.subList(fromIndex, toIndex) 来将列表拆分为更小的列表。你应该使用这个。对于合并部分:

根据维基百科的动画

你应该如何考虑合并两个列表应该相当简单:

首先将两个列表维护为易于从中删除对象的列表。由于此时我们知道列表将被排序,所以我们只对每个列表中的第一个对象(最小元素)感兴趣。

其次,我们只需要比较每个列表的第一个元素,从其各自的列表中删除两者中最小的一个,然后将其添加到我们的排序列表中。我们一直这样做,直到两个列表都为空 - 此时我们已经合并了我们的列表。

在 Java 中,这表明我们应该为合并部分使用数据结构,它允许我们查看每个列表的第一个元素,并快速删除我们感兴趣的元素。在 Java 中,这个数据结构是 LinkedList - ArrayList 两者在这项任务中表现非常糟糕,并且没有提供适当的方法来完成这项任务。 LinkedList 表现为一个队列,并提供了在列表末尾轻松检查和删除对象的方法,例如第一个元素。

因此,您应该重新考虑您的实施策略,并根据您应该如何攻击 MergeSort 算法来简化您的代码。如果这里看起来令人困惑,这里是一个仅使用标准 API 的 Java 中 MergeSort 的示例实现(没有内置排序方法)。

希望对你有帮助。

import java.util.LinkedList;
import java.util.Random;
import java.util.List;

public class Main {

    public static void main(String[] args){

        Random random = new Random();
        LinkedList<Integer> unsorted = new LinkedList<Integer>();
        for(int i = 0; i<100; i++){
            unsorted.add(random.nextInt(100));
        }

        System.out.println("unsorted: " + unsorted.toString());

        List<Integer> sorted = mergeSort(unsorted);

        System.out.println("sorted: " + sorted.toString());
    }

    //Recursive function for sorting a LinkedList
    private static LinkedList<Integer> mergeSort(LinkedList<Integer> unsorted){

        //If the list only contains 1 object it is sorted
        if(unsorted.size() == 1){
            return unsorted;
        }

        //Split the list in two parts and create a new list to store our sorted list
        LinkedList<Integer> left = mergeSort(new LinkedList<Integer>(unsorted.subList(0, unsorted.size()/2)));
        LinkedList<Integer> right = mergeSort(new LinkedList<Integer>(unsorted.subList(unsorted.size()/2, unsorted.size())));
        LinkedList<Integer> sorted = new LinkedList<Integer>();

        //Actual loop for merging the two sublists. Using LinkedLists, this is efficient. (Compared to ArrayList)
        while(!left.isEmpty() || !right.isEmpty()){
            Integer leftInt = left.peekFirst();
            Integer rightInt = right.peekFirst();

            if(!(leftInt == null) && !(rightInt == null)){
                if(leftInt < rightInt){
                    sorted.add(left.pollFirst());
                }
                else{
                    sorted.add(right.pollFirst());
                }
            }
            else if(leftInt == null){
                sorted.add(right.pollFirst());
            }
            else{
                sorted.add(left.pollFirst());
            }
        }

        return sorted;
    }
}

【讨论】:

  • 哈哈哈如果我的老师没有要求我们只使用 ArrayLists 和递归,我会这样做。对不起,我的问题不清楚。我需要算法做的是对使用“大小”创建并使用随机填充的 ArrayList 进行排序。该算法需要使用合并排序路径进行排序。很抱歉,但我的 AP 计算机科学老师确实限制了他希望我们完成工作的方式...:/ 感谢您的帮助
  • 从技术上讲,除了 ArrayList 之外,我的解决方案还可以完成所有这些... .peekFirst() 和 ArrayList.remove(0) 而不是 LinkedList.pollFirst()。那会怎样?
  • 或者它有点复杂,因为如果列表为空,.get(0) 会抛出异常......但它可以通过一点黑客攻击......而且非常低效。我不明白为什么你的 AP 计算机科学老师会强迫你做一个糟糕的实现,无论是在编程方面,还是在学习方面。自从我开始学习计算机科学以来,我从未受到过这样的限制。
  • 是的,这就是我要说的@Dyrborg,我在完成重新格式化后得到了 NullPointerException。明天早上我可能会进去问他为什么。感谢您的帮助!
  • 你可以在这里看到一个 ArrayList 版本:dl.dropboxusercontent.com/u/3258087/Main.java 如你所见,你只需要了解列表为空的情况,然后它就可以工作了。但是删除数组中的第一个元素是非常低效的,因为整个数组需要向左交换一个。
猜你喜欢
  • 2021-09-12
  • 2014-03-31
  • 1970-01-01
  • 2015-09-10
  • 2018-02-12
  • 1970-01-01
  • 2018-10-13
  • 2019-04-24
相关资源
最近更新 更多