【问题标题】:Java doubly linked list pointers to previous nodesJava 双向链表指针指向前一个节点
【发布时间】:2014-12-13 23:10:43
【问题描述】:

我正在制作一种方法来将节点添加到名为“public void add(int index, T value)”的列表中。

此方法会将一个值放入索引中,然后将具有指向列表中下一个和上一个元素的指针。我弄乱了指向以前节点的指针,我一直在坐下来试验,但没有让它工作。

示例:我们有一个包含整数值 [2, 4, 6] 的列表 实例变量: 节点头、尾; int 数量,变化;

内部类的实例变量是: T值; 节点上一个,下一个;

输入:

add(1, 3);
System.out.println(list.toString());
System.out.println(list.backwardsString());

预期输出:

[2, 3, 4, 6]
[6, 4, 3, 2]

到目前为止我的代码:

public void add(int index, T value) {
if (index < 0 || index > amount) {
        throw new IndexOutOfBoundsException("Index is not between 0 and amount!");
    }

    if (value== null) {
        throw new NullPointerException("Value can't be null!");
    }

    if (amount == 0) {
        head = tail= new Node<>(value, null, null);
    }
    else if (index == 0) {
        head = head.prev= new Node<>(value, null, head);
    }
    else if (index == amount) {
        tail = tail.next= new Node<>(value, tail, null);
    } 
    else {
        Node<T> p = head;  
        for (int i = 1; i < index; i++) {
            p = p.next;
        }
        p.next= new Node<>(value, p, p.next);


        p = tail;
        for (int i = amount; i > index; i--) {
            p.prev= new Node<>(value, p.prev, p);
            p = p.prev;
        }*/
    }

    amount++;
    changes++;
}

在这个场合我也会问怎么做

p.prev.next 或 p.next.prev

工作?

【问题讨论】:

    标签: java list pointers linked-list doubly-linked-list


    【解决方案1】:

    您可以通过在 List 类中引入一个空的伪节点来大大简化您的设计。

    由于此节点始终存在,因此您不需要特殊情况,例如:

    if (amount == 0) {
        head = tail= new Node<>(value, null, null);
    }
    else if (index == 0) {
        head = head.prev= new Node<>(value, null, head);
    }
    

    第一个伪节点可以初始化为

    pseudo.next = pseudo;
    pseudo.prev = pseudo;
    

    如果列表为空

    pseudo.next == pseudo.prev
    

    真正的列表开始将是pseudo.next,最后一个列表条目将是pseudo.prev。所以你的 List 实际上是一个环。

    你的搜索循环会变成

       Node<T> p = pseudo.next;  
       for (int i = 0; i < index && p!=pseudo; i++) {
            p = p.next;
       }
    

    但是在这里:

       p.next= new Node<>(value, p, p.next);
    

    您现在必须操纵 p.next.prev 也指向(或更好地引用)非法节点。

    但我把它留作家庭作业——这显然是;-)

    编辑:

    展示哨兵节点的完整列表实现

    公共类列表{

    public class  Node {
        T value = null;
        Node(T v) {
            value=v;
        }
        Node()   {
        }
        public Node getNext() {
            return next;
        }
    
        public Node getPrev () {
            return prev;
        }
        public T getValue() {
            return value;
        }
    
        Node prev = null;
        Node next = null;
    };
    
    private Node pseudo = new Node();
    
    List() {
        pseudo.next = pseudo.prev = pseudo;
    }
    
    public Node getBegin() {
        return pseudo.next;
    }
    
    public Node getEnd() {
        return pseudo;
    }
    
    public boolean add(int index, T value) {
        Node p = pseudo.next;
    
        for (int i = 0; i < index && p!=pseudo; i++) {
            p = p.next;
        }
    
        // Correct for tail insertion
        if(p == getEnd())
            p = p.prev;
    
        Node ptm = p.next;
    
        p.next      = new Node(value);
        p.next.next = ptm;
        p.next.prev = p;
        ptm.prev    = p.next;
    
        return true;
    }
    
    public void delete(int i) {
    
        Node p = pseudo.next;
    
        for (int ix = 0; ix < i && p!=pseudo; ix++) {
            p = p.next;
        }
    
        if(p != getEnd()) {
            Node ptm = p.prev;
            p.prev.next = p.next;
            p.next.prev = ptm;
        }       
    }
    

    }

    【讨论】:

    • 这是一个很难的主题,很难完全掌握它是如何工作的。
    • @Toeffen 你有很多代码只是检查(1)和空列表(2)如果你应该插入头部或(3)尾部。这一切都可以通过使用哨兵节点来规避,参见en.wikipedia.org/wiki/Sentinel_node。在 n0 之后插入节点 n1(带有 tmp 节点 nt)然后简单地变为 {nt = n0.next;n0.next=n1;n1.prev=n0;n1.next=nt;nt.prev=n1;} n1 变为 n1.prev.next = n1.next; n1.next.prev = ne.prev;
    • 索引也可以是介于两者之间的任何东西,而不仅仅是头部或尾部。这段代码可以很好地插入和添加指向下一个节点的指针,但是前面的节点没有连接。
    • @Toeffen 我添加了一个实现 if List 来演示哨兵节点的用法。我错过的是尾部插入的特殊处理,其中当前节点必须是 p.prev 而不是 p.
    猜你喜欢
    • 1970-01-01
    • 2019-04-19
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多