【问题标题】:Java linkedlist - How to copy data?Java 链表 - 如何复制数据?
【发布时间】:2017-04-21 19:06:28
【问题描述】:

我正在尝试编写一个函数,该函数将双向链表中的“n”个节点从前面移动并添加到后面:

public class PetList {
    protected class LinkNode {
        protected LinkNode next;
        protected LinkNode prev;
        protected Pet animal; // note that my data within a node is an object

        public LinkNode() {
            next = prev = null;
        }
    }
    protected LinkNode first;
    protected LinkNode last;

    public PetList() {
        first = last = null;
    }
//...
//... other functions

public void Rotate(int n) {

}

现在我知道如何在后面插入一个节点,例如:

public void insertRear(Pet giraffe) {
    LinkNode temp = new LinkNode();
    temp.animal = new Pet(giraffe);
    if(first == null) {
        first = last = temp;
        return;
    }
    temp.prev = last;
    last.next = temp;
    last = temp;
}

但在我的 Rotate 函数中:

public void Rotate(int n)

我没有对象作为参数。也就是说,我怎样才能创建一个临时链接节点并复制第一个链接节点对象中的数据,然后将我的临时节点移到后面,删除我的第一个节点?还是有另一种更好的方法来做到这一点?感谢您的帮助。

【问题讨论】:

  • 移动数据与复制数据不同
  • 为什么需要一个对象作为参数?您已经说过您只想将列表中的第一件事移到末尾。
  • 取第一个节点,删除它,将下一个节点标记为列表的新头,然后将你的第一个节点放在最后。
  • 扩展@njzk2 答案,使Rotate 递归。
  • 为什么要新建节点并复制数据?您只需移动现有节点,数据将自动跟随。

标签: java object linked-list


【解决方案1】:

应该很简单。以下是如何将一个节点从头部移动到尾部:

public void moveHeadToTail() {
    if (first == null || last == null) {
        throw new IllegalStateException("can't do that on empty list");
    }
    // Detach the first node
    LinkNode temp = first;
    first = temp.next;
    first.previous = null;
    temp.next = null;

    // Put the tmp node at the end
    last.next = temp;
    temp.prev = last;
    last = temp;
}

然后,您可以将其拆分为更好的函数:popHeadpushTail

public LinkNode popHead() {
    if (first == null) {
        throw new IllegalStateException("can't do that on empty list");
    }
    LinkNode temp = first;
    first = temp.next;
    first.previous = null;
    temp.next = null;
    return temp;
}

public void pushTail(LinkNode node) {
    if (last == null) {
        throw new IllegalStateException("can't do that on empty list");
    }
    last.next = node;
    node.prev = last;
    node.next = null;
    last = node;
}

这使得旋转更容易:

public void moveHeadToTail() {
    pushTail(popHead());
}

那么修改以使其适用于n 应该是相当微不足道的。

【讨论】:

  • 您可以通过一次移动整个块来在 O(1) 中进行更新(不计算遍历)。
  • "(不计算遍历)"为什么不计算遍历?
  • 您仍然需要遍历 n 个元素来找到截止点,但您不需要更新每个元素。
  • @shmosel 但是您如何考虑通过排除一些操作来衡量您的复杂性?
  • (我的意思是,是的,它会更有效,但不会改变复杂性。)
【解决方案2】:

我会从列表的开头截取一段长度为n 的节点,同时跟踪截断列表中的第一个和最后一个节点。将first 设置为切断子列表之后的节点,使其成为新的第一个节点。然后,我将通过在旧的最后一个节点和子列表中的第一个节点之间提供双向链接,将子列表附加到末尾。最后将last设置到子列表的末尾,我就完成了。

将您的节点画成纸上的方框,将链接画成指向其他方框的箭头。擦拭并绘制以可视化步骤。那么一切都应该更清楚了。

【讨论】:

    猜你喜欢
    • 2011-06-07
    • 2012-12-05
    • 1970-01-01
    • 2015-02-23
    • 2015-07-19
    • 2011-12-02
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多