【问题标题】:MergeSort not giving correct outputMergeSort 没有给出正确的输出
【发布时间】:2015-06-21 20:26:37
【问题描述】:

我有两个班级:

public class List {
    public Node _head;
}

还有:

public class Node {
    public String _word;
    public Node _next;
}

我在“列表”中有一个构造函数,它获取一个字符串作为参数并将每个单词放在一个单独的节点中,如下所示:

public List(String text) {
    if (text.length() == 0)
        _head = null;
    createList(text);
}

private void createList(String text) {
    int lastIndex=0; 
    String temp;        
    for (int i=0;i<text.length();i++) {
        if (text.charAt(i)==' '|| i==text.length()-1) {
            if (i == 0) { // Space in the begining
                lastIndex=1;
                continue;
            }
            if (i == text.length()-1) { // If we reached to the last char of the string

                if (text.charAt(i) == ' ') { // If it's a space, don't include it
                    temp = text.substring(lastIndex,i);
                } else {
                    temp = text.substring(lastIndex,i+1);
                }
            } else {
                temp = text.substring(lastIndex,i);
            }
            addToBegining(temp);
            lastIndex=i+1;
        }
    }
}

无论如何,当我尝试在链表上使用合并排序时,我无法让它工作。

这是排序代码:

public Node merge_sort(Node h) {
    if (h == null || h._next == null) { return h; }
    Node middle = getMiddle(h);      //get the middle of the list
    Node sHalf = middle._next; middle._next = null;   //split the list into two halfs

    return merge(merge_sort(h), merge_sort(sHalf));  //recurse on that
}

public Node merge(Node a, Node b) {
    Node dummyHead, curr; 
    dummyHead = new Node(); 
    curr = dummyHead;
    while (a !=null && b!= null) {
        if (a._word.compareTo(b._word) <= 0) { 
            curr._next = a; 
            a = a._next; 
        } else { 
            curr._next = b; 
            b = b._next; 
        }
        curr = curr._next;
    }
    curr._next = (a == null) ? b : a;
    return dummyHead._next;
}

public Node getMiddle(Node h) {
    if (h == null) { return h; }
    Node slow, fast; 
    slow = fast = h;
    while (fast._next != null && fast._next._next != null) {
        slow = slow._next; 
        fast = fast._next._next;
    }
    return slow;
}

知道有什么问题吗? 我正在尝试使用字符串“Hello New World A Dawn Is There”创建一个新的 TextList,输出为:“There World”..

【问题讨论】:

  • 为什么要重新发明链表和排序?你不能只用java.util.LinkedListjava.util.Collections.sort吗?
  • @kosmaty 我认为他正在学习实现 LinkedList。您是否尝试在排序之前打印数据?只是为了检查您的所有内容是否确实存在于 LinkedList 中
  • 我正在尝试学习界面。我做到了,结果很好(只是颠倒了)。在我尝试排序之后,输出只是一团糟。

标签: java linked-list nodes mergesort


【解决方案1】:

请如下更改。我认为您忘记将curr 节点分配给if-else 之后的适当值。

    public Node merge(Node a, Node b)
    {
        Node dummyHead, curr;
        dummyHead = new Node();
        curr = dummyHead;
        while (a != null && b != null)
        {
            if (a._word.compareTo(b._word) <= 0)
            {
                curr._next = a;
                curr = a;
                a = a._next;
            }
            else
            {
                curr._next = b;
                curr = b;
                b = b._next;
            }
            curr = curr._next;
        }
        curr._next = (a == null) ? b : a;
        return dummyHead._next;
    }

【讨论】:

  • @Osh24 您可以尝试打印从merge_sort 函数计算和传递的值吗?
  • 您的意思是在递归函数中添加 System.out.print ?我不确定哪些值..
【解决方案2】:

合并排序不适用于链接列表,因为您需要访问列表的中间元素(您将列表分为 2 个子列表)。使用链表,您只能访问列表的第一个元素(单链表)。

尝试使用它是不可行的,因为每次划分列表时都必须先找到指向中间元素的链接。最好尝试以链表的第一个元素为轴的插入排序或快速排序。

编辑: 昨天我手机回复了,没办法分析你的代码。

今天我测试了你的代码。

我用词"ant", "lion", "pig", "rat", "bat", "tiger", "cat", "dog" 创建输入列表并使用merge_sort() 方法。 它的输出是很好的排序列表。

我对您的代码所做的唯一更改是将构造函数添加到 Node()

Node () {
    _word = "";
    _next = null;
}

Node (String word) {
    _word = word;
}

但这只是为了让我更容易创建新节点。

您能说明如何测试您的输出列表吗?

EDIT2: 正如你所说的那样,我没有检查你的代码以将单词与字符串分开)

EDIT3: 您的合并方法还有其他问题,但这是主要问题。

想一想当您尝试合并 2 个列表时您的 merge() 方法是如何工作的: a = {“蚂蚁”、“蝙蝠”、“狗”} b = {“猫”、“狮子”、“老鼠”}

while 循环迭代:

  1. curr = {"ant"} a = { "bat", "dog" } b = { "cat", "lion", "rat"}

  2. curr = {"ant", "bat"} a = { "dog" } b = { "cat", "lion", "rat"}

  3. curr = {"ant" "bat", "cat"} a = { "dog"} b = { "lion", "rat" }

  4. curr = {"ant", "bat", "cat", "dog"} a = { } b = { "lion", "rat" }

  5. a == null,while 循环终止

接下来发生了什么? 您的方法仅从列表 b 中分配一次下一个元素并退出。从 b 中丢失第二个元素(“老鼠”)。

我稍微修改了你的代码,getMiddle() 方法和你的一样:

public Node mergeSort(Node h) {
    if (h._next != null) { // check for recursion if in list left at least 2 elements
        Node middle = getMiddle(h);
        Node sHalf = middle._next; middle._next = null;
        return merge(mergeSort(h), mergeSort(sHalf));
    }
    else { // if only 1 element then no need to sort
        return h;
    }
}

public Node merge(Node a, Node b) {
    Node dummyHead = new Node();
    Node curr = dummyHead; 
    while (a !=null && b!= null) {
        if (a._word.compareTo(b._word) <= 0) {
            curr._next= a; 
            a = a._next; 
        } else { 
            curr._next = b; 
            b = b._next;            
        }
        curr = curr._next;
    }
    // if list a still has some elements, insert them to the end of the curr
    while(a != null) {
        curr._next = a; 
        a = a._next; 
        curr = curr._next;
    }
    // if list b still has some elements, insert them to the end of the curr
    while(b != null) {
        curr._next = b; 
        b = b._next;
        curr = curr._next;
    }
    return dummyHead._next;
}

【讨论】:

  • 您不能使用迭代访问所有元素吗?我认为 OP 正在使用 getMiddle() 函数。
  • 您对使用其他列表的建议有效,但用户正在学习实施。请协助解决问题的要求。
  • 我不是说不可能,而是不适合。对链表使用归并排序是无效的,因为每次划分链表时都需要迭代槽链表以找到中间元素。
  • 我明白,这就是用户想要的。他不关心项目的有效性,而是关心项目的学习。 :)
  • 我正在尝试使用 O(nlogn) 来做到这一点。
猜你喜欢
  • 1970-01-01
  • 2013-02-19
  • 2012-05-22
  • 1970-01-01
  • 1970-01-01
  • 2013-07-30
  • 2015-08-20
  • 2020-05-06
  • 1970-01-01
相关资源
最近更新 更多