【问题标题】:Merging two sorted lists when recursion isn't an option - Java当递归不是一个选项时合并两个排序列表 - Java
【发布时间】:2014-10-07 12:04:39
【问题描述】:

我完全被难住了。我已经在解决方案的示例上查找了示例,并且没有像这样的结构。

目标是以从小到大的排序方式组合两个链表。

问题是它必须使用由已创建列表类的对象调用的方法来完成,该对象接受列表类的另一个对象的列表。

编辑:我假设由于方法签名的形式而无法使用递归。如果不是这样,请纠正我。

即。

 list2.mergeSort(list1.getList()); // getList() is a method that returns the list of 
                                   // that object   

签名看起来像

 public List<Integer> mergeSort(List<Integer> otherList)

在组合列表 1 和另一个列表 2 后,您会将生成的合并列表存储在列表 1 中,并由 mergeSort() 方法返回。

如果另一种形式比我选择的列表形式更好,我应该补充一点,列表可以是一个数组或整数、ArrayList 或其他一些列表或数组形式。

可能的解决方案?

 public List<Integer> mergeSort(List<Integer> otherList){

    List<Integer> temp = new LinkedList<Integer>();

    for(int x = 0; x<list.size(); x++){
        if(list.get(x) < otherList.get(x))
            temp.add(list.get(x));
        else
            temp.add(otherList.get(x));
    }

    list = temp;

    return list;
}

【问题讨论】:

  • 同时遍历两个列表;接下来将两个当前值中的较小者放入合并列表中,仅推进该迭代器。继续,直到两个列表都被完全迭代。
  • 您的排序列表(合并前后)可能有重复元素吗?
  • 是的。关键是如果你有 list 1 = [0, 12, 34, 2] 和 list 2 = [2, 32, 4, 66] 在调用 mergeSort 方法后你的 list 2 现在应该看起来像 list 2 = [0, 2 , 2, 4, 12, 32, 34. 66]

标签: java algorithm list sorting linked-list


【解决方案1】:

简单(推荐用于实际项目)方式:

public MyList<E> mergeSort(Collection<? extends E> list) {
    this.addAll(list);
    Collections.sort(this);
    return this;
}

更详细的方式:

public MyList<E> mergeSort(Collection<? extends E> list1) {
    //Copy this list in another one and clear it
    List<E> list2 = new ArrayList<E>(this);
    this.clear();
    //Merge values until one list is exhausted
    Iterator<? extends E> it1 = list1.iterator();
    Iterator<? extends E> it2 = list2.iterator();
    if (it1.hasNext() && it2.hasNext()) {
        E value1 = it1.next(), value2 = it2.next();
        do {
            if (value1.compareTo(value2) <= 0) {
                this.add(value1);
                if (it1.hasNext()) {
                    value1 = it1.next();
                } else {
                    this.add(value2);
                    break;
                }
            } else {
                this.add(value2);
                if (it2.hasNext()) {
                    value2 = it2.next();
                } else {
                    this.add(value1);
                    break;
                }
            }
        } while (true);
    }
    //copy remaining values
    while (it1.hasNext()) {
        this.add(it1.next());
    }
    while (it2.hasNext()) {
        this.add(it2.next());
    }
    return this;
}

我的类定义如下所示:

public class MyList<E extends Comparable<E>>
    extends ArrayList<E> {

【讨论】:

  • 您的第一个“真正的项目”方式是我尝试过的方式,但它两次添加了第二个列表。我想我命名错了。我会再试一次。
  • 是的,它肯定是添加了第二个被传递两次的列表。
  • 不在我的测试中,我可以看看你是如何创建列表并调用 mergeSort 方法的吗?也许你应该更好地使用@Baldy 的解决方案中的utility functions
  • 列表是随机创建的,使用泛型将添加到每个列表中的项目作为节点。如果我打印出列表,每个列表都有正确数量的元素,但通过后出现问题。我已将值添加到列表中,如下所示: public List getList(){ Node cursor = head; while(cursor.getNext() != null){ list.add(cursor.getData());光标=cursor.getNext(); } 返回列表; } 对不起,您必须复制才能清楚地看到。这给了我该对象的列表。
  • 我在上面键入时调用了 mergeSort 方法。 list2.mergeSort(list1.getList());
【解决方案2】:

我认为您希望就地完成合并?如果是这样,它与普通的合并两个列表问题并没有什么不同。

由于我不熟悉Java,我将编写算法的伪代码版本(假设list1list2都已经排序):

let Y refer to the first element in list2
for X in list1 (traversed in ascending order):
    while Y < X:
        insert Y before X
        change Y to point to the next element
while Y is still a valid reference:
    append Y to list1
    change Y to point to the next element

这里的算法破坏性地修改list1并将list2的每个元素插入到正确的位置。如果您希望在比较相等的元素时首选list2,请将&lt; 更改为&lt;=

【讨论】:

  • 会不会像我上面提供的可能的解决方案(不起作用,所以我不确定我哪里出错了)?
  • 您的解决方案无法遍历 both 列表:您的索引 i 仅来自 list 的索引(我什至不知道 list 是什么是因为它似乎是一个未声明的变量)。
  • 对不起,它是整个班级的一部分,所以它在上面声明。要么我找到了一个可行的解决方案。它很乱,但它有效。
【解决方案3】:

List 迭代器维护 插入顺序,因此它们并非真正设计为执行您想要的操作,尽管您可以在使用 Collections.sort() 合并列表后对列表进行排序。

public List<T> mergeSort(List<T> one, List<T> two) {
    List<T> rc = new ArrayList<>(one.size() + two.size());
    rc.addAll(one);
    rc.addAll(two);
    Collections.sort(rc);
    return rc;
}

您可以在此处添加Comparator 以控制排序。

最好使用Set 集合,因为它们会根据类型自动排序。如果你没问题,方法如下:

public Set<T> mergeSort(Set<T> one, Set<T> two) {
    Set<T> rc = new TreeSet<>(one);
    rc.addAll(two);
    return rc;
}

同样,您也可以在此处添加Comparator

不完全是您想要的,但不是扩展ArrayListTreeSet,而是您可以在任何地方使用的通用方法。对于你的问题,我会这样使用它:

list1 = Utility.mergeSort(list1, list2);

【讨论】:

  • 您的解决方案的问题以及我遇到问题的原因是您对 mergeSort() 的签名。 mergeSort 方法只传递要添加到调用该方法的对象的第一个列表的第二个列表。两个列表都不会同时传递给这个方法。
【解决方案4】:

你可以构造一个Iterable,它可以合并另外两个Iterables,只要它们是Comparable

class MergedList<T extends Comparable<T>> implements Iterable<T> {
    // The two Iterables we are merging.
    private final Iterable<T> a;
    private final Iterable<T> b;

    // Varargs version left to the student.
    public MergedList(Iterable<T> a, Iterable<T> b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            // Grab iterators.
            private final Iterator<T> ia = a.iterator();
            private final Iterator<T> ib = b.iterator();
            // Prime both pumps.
            private T na = ia.hasNext() ? ia.next() : null;
            private T nb = ib.hasNext() ? ib.next() : null;
            // Next to deliver.
            private T n = null;

            @Override
            public boolean hasNext() {
                if (n == null) {
                    // Pick one - either null means the other one - otherwise compare.
                    n = na == null ? nb : nb == null ? na : na.compareTo(nb) < 0 ? na : nb;
                    if (n != null) {
                        // Consume one.
                        if (na != null && n == na) {
                            // Get next from a.
                            na = ia.hasNext() ? ia.next() : null;
                        } else if (nb != null && n == nb) {
                            // Get next from b.
                            nb = ib.hasNext() ? ib.next() : null;
                        }
                    }
                }
                return n != null;
            }

            @Override
            public T next() {
                T next = n;
                n = null;
                return next;
            }

        };
    }
}

public void test() {
    List<String> a = Arrays.asList("A", "C", "E");
    List<String> b = Arrays.asList("B", "D", "F");
    for (String s : new MergedList<>(a, b)) {
        System.out.println(s);
    }
}

【讨论】:

  • 我不是要添加更多我所说的方法或更改mergeSort签名的基本结构。
  • @EMMERZOH - 那么你注定要建立一个新的列表,如果列表变大,它可能会咬你。我的解决方案不再占用内存并即时合并两个列表。
【解决方案5】:
   public List<Integer> mergeSort(List<Integer> otherList){
        List<Integer> list1 = new ArrayList<>(); // this should be list1
        list1.addAll(otherList);

        /** can also use Collections.sort(list1); */
        Collections.sort(list1,new Comparator<Integer>() {

            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2); //Change to o2.CompareTo(o1) for descending order
            }
        });
        return list1;
    }

【讨论】:

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