Kotlin 我的代码与我在谷歌上找到的检查代码是否正确的代码相比有什么不同?

Kotlin 我的代码与我在谷歌上找到的检查代码是否正确的代码相比有什么不同?,kotlin,data-structures,doubly-linked-list,Kotlin,Data Structures,Doubly Linked List,简而言之,问题是,我想删除双链表的最后一个元素,我编写了这个函数 fun deleteLast(){ if(isEmpty()){println("list is empty")} if (head!=null && head?.nextNode == null){ head = null }else { tail = tail?.previousNode tail?.nextNode =

简而言之,问题是,我想删除双链表的最后一个元素,我编写了这个函数

fun deleteLast(){
    if(isEmpty()){println("list is empty")}
    if (head!=null && head?.nextNode == null){
        head = null
    }else {
        tail = tail?.previousNode
        tail?.nextNode = null
    }
}
我在没有遍历的情况下访问了tail,并将其上一个作为newtail,下一个作为newtail(旧tail)设置为null。我的结果是令人满意的。 写完这篇文章后,我点击谷歌来检查这是否正确,所以,我发现了这个

void pop_back() {
if(this.head != null) {
//1. if head in not null and next of head
//   is null, release the head
if(this.head.next == null) {
  this.head = null;
} else {
  
  //2. Else, traverse to the second last 
  //   element of the list
  Node temp = new Node();
  temp = this.head;
  while(temp.next.next != null)
    temp = temp.next;
  
  //3. Change the next of the second 
  //   last node to null and delete the
  //   last node
  Node lastNode = temp.next;
  temp.next = null; 
  lastNode = null;
  }
 }
}

我想问一下我的代码是否正确,我只想让你们大师们检查一下。提前谢谢

问题只包含一个片段,而不是一个,因此为了便于讨论(基于现有代码和注释),我假设完整代码如下所示:

class Node<T>(var previousNode: Node<T>?, var nextNode: Node<T>?, var value: T)

class DoublyLinkedList<T>(var head: Node<T>?, var tail: Node<T>?) {
    fun isEmpty() = head == null

    // …other methods…

    fun deleteLast(){
        if(isEmpty()){println("list is empty")}
        if (head!=null && head?.nextNode == null){
            head = null
        }else {
            tail = tail?.previousNode
            tail?.nextNode = null
        }
    }
}
类节点(变量previousNode:Node?,变量nextNode:Node?,变量值:T)
类双链接列表(变量头:节点?,变量尾:节点?){
fun isEmpty()=head==null
//…其他方法…
最后的乐趣{
if(isEmpty()){println(“列表为空”)}
if(head!=null&&head?.nextNode==null){
头=空
}否则{
tail=tail?.previousNode
tail?.nextNode=null
}
}
}
鉴于此,您的代码似乎是正确的。  有几点可以解决*,例如:

  • 在第二个
    if
    中,为了安全起见,我认为还需要将
    tail
    设置为null
  • 在第二个和第三个分支中,您可能希望将要删除的节点中的
    previousNode
    nextNode
    引用设置为null,以便使用仍有引用的任何其他代码。  (这也可能会给垃圾收集器一个额外的提示,尽管不需要)
  • 与其调用
    isEmpty()
    ,不如更简单、更一致地检查
    head
    是否为null
  • 我会在第二个
    if
    之前添加一个
    else
    。  事实上,代码适用于空列表,但这可能只是运气;如果其他分支都不能在空列表上调用,那么它将更加健壮。  (在某些情况下,这可能会让编译器智能转换
    head
    为不可空;但在这里不会发生这种情况,因为它是可变的。)
  • 在生产代码中,您不会像那样打印到标准输出。  如果允许对空列表调用
    deleteLast()
    ,则无需打印任何内容;如果不是(这更常见),您将抛出一个异常。  (该方法将有一个文档注释来解释这一点。)
  • 格式可以改进
(*根据我的经验,任何代码都可以改进,即使是您以前使用过多次的代码!)

但是,你不能直接将你的代码与谷歌源代码进行比较,因为它看起来像是针对一个单链表。

单链表是一种简单得多的结构。  它所拥有的只是对
头部
节点的引用;具有对
下一个
节点的引用(以及,可能是对存储在节点中的数据的引用);等等  因此,到达列表末尾的唯一方法是遍历所有节点,正如谷歌源代码所做的那样。  (这也意味着通常没有必要使用单独的类来表示整个列表;只需引用第一个节点即可。  使用递归方法可以简洁地编写许多操作。  您还可以使其不可变,这有许多优点;这是某些语言中的主要数据结构。)


但是,您的列表直接引用了最后一个节点,这当然避免了遍历整个列表来查找它。  正如您的代码所演示的,这意味着在双链接列表中某些操作要高效得多。  但也有相应的缺点:每个节点占用更多内存;更改列表时,有更多的引用需要更新;列表更容易进入不一致状态;而且它不太适合于不可变的列表。)

如果不查看代码的其余部分,就很难判断这一点。(我试着猜测,但弄不清楚如何将
head
tail
previousNode
nextNode
…)它是双链接列表,先生&我在节点类构造函数中声明previous、next和node值,在双链接列表类主体中声明head和tail作为类型节点。先生,您解决了我的问题!非常感谢你!