在链表末尾添加元素

9

我是一名有用的助手,可以为您进行翻译。

我正在学习一项考试,以下是一道来自旧考试的问题:

我们有一个带有列表头的单向链表,声明如下:

class Node {
    Object data;
    Node next;
    Node(Object d,Node n) {
        data = d;
        next = n;
    }
}

编写一个方法void addLast(Node header, Object x),将x添加到列表末尾。

我知道如果我实际上有这样的东西:

LinkedList someList = new LinkedList();

我可以通过以下方式将项目添加到末尾:

list.addLast(x);

但是我在这里怎么做呢?

1
为什么需要传递节点头来将某些内容附加到列表末尾? - therin
编写自己的代码实现 addLast(Node header, Object x) 方法,用于在链表末尾添加元素。可搜索关键词 “Java 单向链表末尾添加元素” 以获取更多信息。 - Deepak
1
@therin - 可能要问他的教授。 - JonH
@therin,这就是确切的问题,我不知道。 - John
尝试将该方法作为静态方法添加到Node类中,并循环到Node头的末尾,然后将新节点添加到该列表的末尾。 - therin
9个回答

17
class Node {
    Object data;
    Node next;
    Node(Object d,Node n) {
        data = d ;
        next = n ;
       }

   public static Node addLast(Node header, Object x) {
       // save the reference to the header so we can return it.
       Node ret = header;

       // check base case, header is null.
       if (header == null) {
           return new Node(x, null);
       }

       // loop until we find the end of the list
       while ((header.next != null)) {
           header = header.next;
       }

       // set the new node to the Object x, next will be null.
       header.next = new Node(x, null);
       return ret;
   }
}

是的,总有一种递归循环的方法。使用 header == null 作为基本情况(您将停止的地方),并调用 addLast 与 header.next。 - therin
所以我会让if语句只返回; 然后最后的header.next是header.next=addLast(header,null)吗? - John
有点像,你需要通过递归循环传递x:addLast(header,x),然后如果header == null,则创建新节点,将X添加到其中,并返回新节点。 如果不在基本情况下,您应该返回addLast的结果。 - therin
你的代码运行时间为O(n),但这个操作应该是O(1)。如果你跟踪尾节点,就不需要遍历列表中的每个元素。你所要做的就是更新尾部指向新节点。 - TomDane
@TomDane 问题陈述指出,我们必须将头节点作为输入,同时将其附加到列表末尾。 - therin

8

您想使用循环遍历整个链表,并检查每个节点的“下一个”值。最后一个节点将是其下一个值为null的节点。只需将此节点的下一个值设置为您使用输入数据创建的新节点即可。

node temp = first; // starts with the first node.

    while (temp.next != null)
    {
       temp = temp.next;
    }

temp.next = new Node(header, x);

那就是基本思路。当然,这只是伪代码,但应该足够简单易懂。

3
最重要的部分是基本情况,即首个为空。应适当处理(例如不要抛出NullPointerException异常)。 - therin

4

如果你跟踪尾节点,就不需要遍历列表中的每个元素。

只需更新尾节点指向新节点即可:

AddValueToListEnd(value) {
    var node = new Node(value);

    if(!this.head) { //if the list is empty, set head and tail to this first node
        this.head = node;
        this.tail = node;
    } else {
        this.tail.next = node; //point old tail to new node
    }
        
    this.tail = node; //now set the new node as the new tail
}

简单来说:

  • 创建一个带有给定值的新节点
  • 如果链表为空,则将头和尾指向新节点
  • 如果链表不为空,则将旧尾部的next指向新节点
  • 在任何情况下,更新尾指针为新节点

5
点赞O(1)。 - user669132
2
当您需要添加多个元素到末尾时,这将非常有用,无需每次滚动整个列表。 - Georgy Gobozov
@tomdane this.tail = node; 不会覆盖 this.tail.next 吗? - arjayads
1
@arjayads 不,它不会覆盖。把tail想象成不是节点本身,而只是指向任何节点的指针。首先,我们使用tail指针来设置节点的.next属性。然后,我们将tail指向另一个节点。但是前一个节点保持不变。 - TomDane

4
public static Node insertNodeAtTail(Node head,Object data) {
               Node node = new Node(data);
                 node.next = null;
                if (head == null){
                    return node;
                }
                else{
                    Node temp = head;
                    while(temp.next != null){
                        temp = temp.next;
                    }
                    temp.next = node; 
                    return head;
                }        
    }

1

这是一个关于你链表类的部分解决方案,我把实现的其他部分留给了你,并且也把作为链表一部分的尾节点的好建议留给了你。

节点文件:

public class Node 
{
    private Object data; 
    private Node next; 

    public Node(Object d) 
    { 
        data = d ;
        next = null;
    }

    public Object GetItem()
    {
        return data;
    }

    public Node GetNext()
    {
        return next;
    }

    public void SetNext(Node toAppend)
    {
        next = toAppend;
    }
}

这里是一个链表文件:

public class LL
{
    private Node head;

    public LL()
    {
        head = null;
    }

    public void AddToEnd(String x)
    {
        Node current = head;

        // as you mentioned, this is the base case
        if(current == null) {
            head = new Node(x);
            head.SetNext(null);
        }

        // you should understand this part thoroughly :
        // this is the code that traverses the list.
        // the germane thing to see is that when the 
        // link to the next node is null, we are at the 
        // end of the list.
        else {
            while(current.GetNext() != null)
                current = current.GetNext();

            // add new node at the end
        Node toAppend = new Node(x);
            current.SetNext(toAppend);
        }
    }
}

0

addLast() 需要进行一些优化,因为 addLast() 内部的 while 循环具有 O(n) 的复杂度。以下是我的 LinkedList 实现。运行代码 ll.addLastx(i) 一次,然后再运行 ll.addLast(i),您可以看到 addLastx() 和 addLast() 的处理时间有很大的差异。

Node.java

package in.datastructure.java.LinkedList;

/**
* Created by abhishek.panda on 07/07/17.
*/
public final class Node {
    int data;
    Node next;

    Node (int data){
       this.data = data;
    }
    public String toString(){
      return this.data+"--"+ this.next;
    }
}

LinkedList.java

package in.datastructure.java.LinkedList;
import java.util.ArrayList;
import java.util.Date;

public class LinkedList {

    Node head;
    Node lastx;
    /**
     * @description To append node at end looping all nodes from head
     * @param data
     */
    public void addLast(int data){

        if(head == null){
            head = new Node(data);
            return;
        }
        Node last = head;
        while(last.next != null) {
            last = last.next;
        }
        last.next = new Node(data);
    }


    /**
     * @description This keep track on last node and append to it
     * @param data
     */
    public void addLastx(int data){

        if(head == null){
            head = new Node(data);
            lastx = head;
            return;
        }
        if(lastx.next == null){
            lastx.next = new Node(data);
            lastx = lastx.next;
        }

    }

    public String toString(){
        ArrayList<Integer> arrayList = new ArrayList<Integer>(10);
        Node current = head;
        while(current.next != null) {
            arrayList.add(current.data);
            current = current.next;
        }
        if(current.next == null) {
            arrayList.add(current.data);
        }
        return arrayList.toString();
    }


    public static void main(String[] args) {
        LinkedList ll = new LinkedList();
        /**
         * @description Checking the code optimization of append code
         */
        Date startTime = new Date();
        for (int i = 0 ; i < 100000 ; i++){
            ll.addLastx(i);
        }
        Date endTime = new Date();
        System.out.println("To total processing time : " + (endTime.getTime()-startTime.getTime()));
        System.out.println(ll.toString());
    }

}

0
遍历指向 null 的链表的最后一个元素,然后将下一个指针修改为指向具有数据=对象和下一个指针=null的新节点。

0

这里有一个提示,你有一个节点图形的链表,并且你始终保留对头部的引用,它是linkedList中的第一个节点。
next指向链表中的下一个节点,因此当next为null时,你已经到达了列表的末尾。


0
上述程序可能会引发NullPointerException。这是一种更简单的方式在linkedList末尾添加元素。
public class LinkedList {
    Node head;

    public static class Node{
        int data;
        Node next;

        Node(int item){
            data = item;
            next = null;
        }
    }
    public static void main(String args[]){
        LinkedList ll = new LinkedList();
        ll.head = new Node(1);
        Node second = new Node(2);
        Node third = new Node(3);
        Node fourth = new Node(4);

        ll.head.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = null;

        ll.printList();
        System.out.println("Add element 100 to the last");
        ll.addLast(100);
        ll.printList();
    }
    public void printList(){
        Node t = head;
        while(n != null){
            System.out.println(t.data);
            t = t.next;
        }

    }

    public void addLast(int item){
        Node new_item = new Node(item);
        if(head == null){
            head = new_item;
            return;
        }
        new_item.next = null;

        Node last = head;
        Node temp = null;
        while(last != null){
            if(last != null)
                temp = last;
            last = last.next;
        }   

        temp.next = new_item;   
        return;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接