插入排序 - 交换节点

时间:2013-03-11 03:33:17

标签: java algorithm sorting data-structures

我在java中为插入排序编写了以下例程,用于双向链接列表,该列表将节点中的数据交换为sort& amp;它工作正常。但是,我试图弄清楚如何实际交换节点链接以实现插入排序。我尝试了很多选项,但都失败了,因为它是节点引用的对象引用,改变它们会混淆和放大。打破清单。任何指针将不胜感激。

Node类(内部类):

   private class Node {
    T data;
    Node next;
    Node prev;
}

排序例程

   public void sort() {
    if(isEmpty()) {
        throw new RuntimeException("List is empty");
    }
    Node current = head;
    while(current != null) {
        for(Node prev=current; prev.prev != null; prev = prev.prev) {
            if(prev.data.compareTo(prev.prev.data) <= 0) {
                T tmp = prev.data;
                prev.data = prev.prev.data;
                prev.prev.data = tmp;
            }
        }
        current = current.next;
    }
}

EDIT1:

感谢lhuang提供交换节点的方法。有用。实际答案在于Java通过值复制并传递引用,而不是对象(参考http://www.javaworld.com/javaqa/2000-05/03-qa-0526-pass.html)。因此,您应该将节点交换传递给其他方法,而不是尝试在同一个地方和因此,除了要交换的两个节点之外,它不会影响其余节点。

我将我的例程修改为以下

public void sort() {
    if(isEmpty()) {
        throw new RuntimeException("List is empty");
    }
    Node current = top;
    while(current != null) {
        for(Node prev=current; prev != null && prev.prev != null; prev = prev.prev) {
            if(prev.data.compareTo(prev.prev.data) <= 0) {
                swap(prev,prev.prev);
            }
        }
        current = current.next;
    }
}

具有这种逻辑的最后一个问题是当交换时电流总是落后&amp;在该逻辑中,相同的两个节点被处理两次。有没有办法减轻这种影响,即在交换后恢复其原始位置的电流?

2 个答案:

答案 0 :(得分:2)

您需要相应地更新node1和node2的上一个和下一个节点。

1,如果一个节点是头部,则更新头部。

2,如果node1在node2之前,则不能只更新node1.prev = node2.prev。它将在列表中引入一个循环。

public void swap(Node node1, Node node2) {
    if (node1 == null || node2 == null) {
        throw new IllegalArgumentException(
                "The nodes couldn't be null");
    }

    if (node1 == node2) {
        return;
    }

    // make sure node1 is before node2
    if (node1.getPrev() == node2) {
        Node temp = node2;
        node2 = node1;
        node1 = temp;
    }

    Node node1Prev = node1.getPrev();
    Node node1Next = node1.getNext();
    Node node2Prev = node2.getPrev();
    Node node2Next = node2.getNext();

    node1.setNext(node2Next);
    if (node2Next != null) {
        node2Next.setPrev(node1);
    }

    node2.setPrev(node1Prev);
    if (node1Prev != null) {
        node1Prev.setNext(node2);
    }

    if (node1 == node2Prev) {
        node1.setPrev(node2);
        node2.setNext(node1);
    } else {
        node1.setPrev(node2Prev);
        if (node2Prev != null) {
            node2Prev.setNext(node1);
        }

        node2.setNext(node1Next);
        if (node1Next != null) {
            node1Next.setPrev(node2);
        }
    }

    if (node1 == head) {
        head = node2;
    } else if (node2 == head) {
        head = node1;
    }
}

对于问题2,您可以在交换之前检查prev。如果是当前的,则将当前设置为prev.prev。

while(current != null) {
    for(Node prev=current; prev != null && prev.prev != null; prev = prev.prev) {
        if(prev.data.compareTo(prev.prev.data) <= 0) {
            if (prev==current) {
                current=prev.prev;
            }
            swap(prev,prev.prev);
        }
    }
    current = current.next;
}

顺便说一下,您也可以尝试减少交换操作。由于您正在对链表进行排序,因此删除和插入元素非常容易。所以,找出适合当前的地方;从原始位置删除它并将其插入。当然,你需要注意一些细节。

答案 1 :(得分:0)

分配节点引用而不仅仅是数据。确保更新两个交换节点左侧和右侧节点的“下一个”和“上一个”,以及交换节点本身。最后,确保在交换后继续使用正确的节点进行迭代。