仅当首先添加最小数量时才对链接列表进行Java合并排序

时间:2018-11-21 03:05:35

标签: java sorting mergesort

当我在链接列表中插入数字时,仅当第一个数字最小时,它才对所有内容进行排序。这是我得到的意外行为:

我按此顺序插入数字-200、25、473、23、390

如果我像上面那样对列表进行排序并显示,我会得到-200、390、473

如果我将200更改为900,然后对列表进行排序,则只会显示900

仅当我将200更改为列表中的最小数字(如1(或小于23的任何数字))时,它才起作用,然后它为我提供了正确的输出1、23、25、390、473

对于链接列表,我在列表的后面插入元素,这是代码:

public void insertAtBack(IntegerElement elem) {
    if (isFull()) {
        System.out.println("Unable to insert node into full list");
    } else {
        Node temp = new Node(elem);
        if (isEmpty()) {
            head = temp;
        } else {
            Node current = head;
            while (current.getLink() != null) {
                current = current.getLink();
            }
            current.setLink(temp);
        }
    }

}

这是我用于合并排序的代码:

public Node getMiddle(Node node) {
    if (node == null) 
        return node;

    Node fastptr = node.getLink(); 
    Node slowptr = node; 

    // Move fastptr by two and slow ptr by one 
    // Finally slowptr will point to middle node 
    while (fastptr != null) { 
        fastptr = fastptr.getLink(); 
        if(fastptr != null) { 
            slowptr = slowptr.getLink(); 
            fastptr = fastptr.getLink(); 
        } 
    } 

    return slowptr; 
}

public Node merge(Node left, Node right)  { 

    Node tempHead = new Node(), curr;

    curr = tempHead;

    while(left != null && right != null) {
        if(left.getData().getValue() <= right.getData().getValue()) {
            curr.setLink(left);
            left = left.getLink();
        }else {
            curr.setLink(right);
            right = right.getLink();
        }

        curr = curr.getLink();
    }

    curr.setLink((left == null) ? right : left);

    return tempHead.getLink();

}

/**
 * This method utilizes merge sort algorithm
 * 
 * @param node - Pass in head first
 * 
 */
public Node sort(Node node) {
    // Base case : if head is null 
    if (node == null || node.getLink() == null)
        return node; 

    // get the middle of the list 
    Node middle = getMiddle(node);
    Node nextofmiddle = middle.getLink();

    // set the next of middle node to null 
    middle.setLink(null);

    // Merge the left and right lists 
    return merge(sort(node), sort(nextofmiddle));
}

感谢您的帮助

1 个答案:

答案 0 :(得分:1)

您的排序例程看起来很棒。该错误似乎是您从排序例程返回的方式。如果您将排序方式称为就地排序,即

sort(head);
System.out.println(head);

旧磁头未更新为sort()返回的新磁头。请注意,在测试用例中显示的节点总是如何从旧的头开始。如果未排序列表中的旧头正好是排序列表中的新头,则此似乎有效,如您的上一个示例。另一方面,如果在排序过程中移动了旧的头节点,那么您将仅从旧的头向后移动的位置看到列表的其余部分。从列表开头到旧头的节点超出范围时将被垃圾回收。

解决方法是将呼叫者中列表的开头设置为sort()返回的标题,这是列表的新标题:

head = sort(head);
System.out.println(head);

这是您的代码被重写,它再现了您的错误以说明问题:

class Main {
    public static void main(String[] args) {
        Node head = new Node(200, new Node(25, new Node(473, new Node(23, new Node(390, null)))));

        System.out.println("Example 1 (correct):");
        System.out.println(head);
        head = sort(head);
        System.out.println(head);

        head = new Node(200, new Node(25, new Node(473, new Node(23, new Node(390, null)))));

        System.out.println("\nExample 1 (incorrect):");
        System.out.println(head);
        sort(head);
        System.out.println(head);

        head = new Node(900, new Node(25, new Node(473, new Node(23, new Node(390, null)))));

        System.out.println("\n\nExample 2 (correct):");
        System.out.println(head);
        head = sort(head);
        System.out.println(head);

        head = new Node(900, new Node(25, new Node(473, new Node(23, new Node(390, null)))));

        System.out.println("\nExample 2 (incorrect):");
        System.out.println(head);
        sort(head);
        System.out.println(head);

        head = new Node(1, new Node(25, new Node(473, new Node(23, new Node(390, null)))));
        System.out.println("\n\nExample 3 (accidentally works, because the old head is still the new head):");
        System.out.println(head);
        sort(head);
        System.out.println(head);
    }

    static Node getMiddle(Node node) {
        Node fastptr = node.link; 
        Node slowptr = node; 

        while (fastptr != null) { 
            fastptr = fastptr.link; 

            if (fastptr != null) { 
                slowptr = slowptr.link;
                fastptr = fastptr.link; 
            }
        } 

        return slowptr; 
    }

    static Node merge(Node left, Node right) { 
        Node temp = new Node(-1, null);
        Node curr = temp;

        while (left != null && right != null) {
            if (left.data < right.data) {
                curr.link = left;
                left = left.link;
            }
            else {
                curr.link = right;
                right = right.link;
            }

            curr = curr.link;
        }

        curr.link = left == null ? right : left;
        return temp.link;
    }

    static Node sort(Node node) {
        if (node == null || node.link == null) {
            return node; 
        }

        Node middle = getMiddle(node);
        Node next = middle.link;
        middle.link = null;
        return merge(sort(node), sort(next));
    }
}

class Node {
    public int data;
    public Node link;

    public Node(int data, Node link) {
        this.data = data;
        this.link = link;
    }

    public String toString() {
        return this.data + (this.link != null ? "->" + this.link : "");
    }
}

输出:

Example 1 (correct):
200->25->473->23->390
23->25->200->390->473

Example 1 (incorrect):
200->25->473->23->390
200->390->473


Example 2 (correct):
900->25->473->23->390
23->25->390->473->900

Example 2 (incorrect):
900->25->473->23->390
900


Example 3 (accidentally works, because the old head is still the new head):
1->25->473->23->390
1->23->25->390->473

Try it!