【问题标题】:How to delete tail in Double Link List?如何删除双向链表中的尾部?
【发布时间】:2021-03-18 07:30:05
【问题描述】:

我的老师在这个活动中指导我们如何删除双链表的尾部。他创建了一个循序渐进的过程或算法供我们遵循。我跟着它,但它不起作用。或者,也许我追错了。这是算法

检查列表是否为空

  • 如果不为空
    • 检查列表中是否只有一个节点
      • 如果只有一个节点,设置头尾引用为空。
      • 如果有多个节点
        • 创建一个指向下一个尾部的 temptail (tail.prev)
        • 将tail的prev和temptail的next设置为null
        • 将 temptail 值分配给尾部

这是我的代码

    public void delTail(){
    DoubleNode temp;
    
   if(isEmpty()){
       return;
   }
   else if(!isEmpty()){
       if(head == tail){
           head = tail = null;
       }
       else{
            temp = tail.next;
            tail.prev = null;
            temp.next = null;
            temp = tail;
       }
   }
    
}

这是我看到的错误error in my terminal

我认为我是否正确地遵循它?非常感谢您的帮助:)

这是我的构造函数*

public class DoubleNode{

public DoubleNode prev;
public int data;
public DoubleNode next;

public DoubleNode(int d){
    this(null, d, null);
}
public DoubleNode(DoubleNode p, int d, DoubleNode n){
    prev = p;
    data = d;
    next = n;
}
}

这是 mt 完整的算子代码*

public class operator{
DoubleNode head;
DoubleNode tail;
DoubleNode laman;

String output = "";

public operator(){
    head = tail = null;
}
public boolean isEmpty(){
    return head == null;
}
public void addHead(int i){
    
    if(isEmpty()){
      head = tail =new DoubleNode(i);
    }
    else{
        head = new DoubleNode(null, i, head);
        head.prev = head;
    }
}
public void addTail(int i){
    DoubleNode last = new DoubleNode(i);  
    if(isEmpty()){
        head = tail = new DoubleNode(i);
    }
    else{
      tail.next = last;
      tail = last;
    }
}
public void delHead(){
    DoubleNode temp = head.next; 
    if(head==tail){ //this if condition is testing if the head and tail is one only, 
        head = tail =null;  //if there is only one this will set the tail and head to null
    }
    else{
        head = head.next;
        head = temp;

    }
}

public void delTail(){
        DoubleNode temp;
        if(isEmpty()) {  
            return;  
        }  
        else {  
            if(head != tail) {   
            tail = tail.prev;
            temp = tail;
               
            }
            
            else {  
                head = tail = null;  
            }  
        }  
}
public void display(){
    DoubleNode tmp = head;
    output = "<html>";
    
    for(tmp = head; tmp != null; tmp = tmp.next){
        output = output + "<br>" + tmp.data + "<b>" + "<br>";
        
    }
    output = output + "</html>";
}
}

到目前为止,这是我的全部代码,我有一个带有 jframe 的主类,但我认为它很好,因为我也将它用于单个链接列表。但是我在双链接列表中确实有一个关于删除最后一个节点的问题

【问题讨论】:

  • 我的代码有什么问题?您看到了什么错误或问题?
  • 代码 sn-p 与伪代码不匹配...在 DLL 中 tail.next 总是为空(记住 tail 在末尾,所以没有下一个)。删除尾部时tail.prev 实际上指向您希望尾部现在的样子.. 所以tail = tail.prev; tail.next = null; 似乎就是您所需要的。 temp 永远不会被使用 - 除非你想保存旧的 tail,这样你就可以清除它的“prev”以帮助垃圾收集。
  • 我的 if else 条件是否有效?这就是问题所在吗?我尝试了我在这里红色的所有建议,但没有一个有效。
  • 请注意,您添加的代码中还有许多其他错误:1) 您有双重分配,例如 head = head.next; head = temp; 2) 您并不总是维护 prevnext正确。请注意,删除node 时,您需要将node.prev.next 指向node.next,将node.next.prev 指向node.prev。插入 node 时,您还需要调整引用:node.next = after.next; node.prev = after; node.next.prev = node; after.next = node;after 将是您插入之后的节点)。
  • 你还需要考虑当你只有一个节点时你会做什么:head == tail应该是真的吗? head.next == headhead.prev == head 应该是真的吗?如果不是,那么您需要处理这种特殊情况。

标签: java constructor linked-list double tail


【解决方案1】:

您的问题是您只是分配给temp,但实际上并没有使用它。此外,您没有正确地将链接设置回前一个元素。

假设tail.next 再次指向head,您可能会执行以下操作:

tail.prev.next = tail.next; //you might need to check for `tail.prev` being null 
tail.next.prev = tail.prev; //you might need to check for `tail.next` being null
//delete tail

举例说明:

A -next-> Tail -next-> Head
^---prev--+  ^---prev--+

第 1 步:

+----next--------------V
A         Tail -next-> Head
^---prev--+  ^---prev--+

第 2 步:

+----next--------------V
A         Tail -next-> Head
^---prev--+            |
^--------------prev----+

实际上如果tail.next == head 删除尾部与删除任何其他节点没有什么不同。

【讨论】:

  • 我试着按照你的指示去做?但是你能检查一下我上面的 if 和 else 条件吗?我的代码是否过多或必要?
  • @Bianxzy 这取决于您是否真的希望headtail 指向彼此。如果是这样,您基本上只需要以下检查:head == null(在这种情况下,tail 也应该为空)表示列表为空。 head == tail 表示您只有一个元素并且可以删除它。其他任何事情都意味着您需要处理 prevnext 引用。
  • 我的代码似乎找不到 tail.prev 引用,当我做 head.next = null;我输入的整个数字将被删除,除了头部。当!我已经坚持了 2 天了。我知道我必须成为一名程序员才能做到这一点
  • @Bianxzy 好吧,如果不知道您到底在做什么,就很难知道发生了什么。访问tail.prev 应该独立于head.next = null。 - 要自己解决这个问题,您应该学习如何使用调试器单步执行您的代码,看看它到底在做什么。
【解决方案2】:

您的else 块中有两个错误:

  • 您永远不会更改 tail 引用。最后一条语句实际上应该是对tail 的赋值。

  • 您似乎认为tail 有一个非空的next 引用,但这是矛盾的。尾部应该是最后一个节点,因此它的next 引用将始终为空(除非您应该创建一个循环 列表)。因此,temp 将为 null,而语句 temp.next = tail 将触发 Null 指针异常。

    tail 更有趣的属性是它的prev 属性,它指的是当前尾节点被移除后将成为tail 的节点。这个tail.prev 在您的作业中明确提及。

所以:

   else {
        temp = tail.prev; // <--- should point to the new tail
        tail.prev = null;
        temp.next = tail;
        tail = temp;  // <--- reverse the assignment
   }

其他几个问题...

addHead 中,您没有正确设置prev 属性。你让它成为一个自我参考。意识到head 已经在引用新节点。变化:

head.prev = head;

到:

head.next.prev = head;

addTail 中缺少对 prev 的分配。变化:

tail.next = last;
tail = last;

到:

tail.next = last;
last.prev = tail; // needed!
tail = last;

delHead 中,您必须确保新头的prev 为空。所以改变:

head = temp;

到:

head = head.next;
head.prev = null;

注意:在那个方法中你不需要DoubleNode temp = head.next;

【讨论】:

  • 我复制了这个确切的代码并尝试使用你给出的逻辑,因为它确实有意义。但似乎我的代码无法确定 tail.prev 在哪里?
  • 那是什么意思?我想你有一个定义prevnext 的类,对吧?您可以编辑您的问题并添加构造函数代码吗?
  • 我已经按照你说的编辑并添加了我的构造函数
  • 您的代码中有几个问题。见补充回答。
  • 我复制了您为 addHead、addTail 和 delHead 提供的代码,所有这些都有效,但似乎我无法解决 delTail 的问题。而head.next.prev = head,它让我很困惑,我真的很想知道它是如何工作的
猜你喜欢
  • 2016-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-29
  • 1970-01-01
  • 1970-01-01
  • 2016-07-23
  • 2018-07-31
相关资源
最近更新 更多