【问题标题】:For a singly linked list, does a new node always have to be added as the first element?对于单链表,是否总是必须添加一个新节点作为第一个元素?
【发布时间】:2018-10-09 05:08:38
【问题描述】:

通常在单链表中,你是否总是添加一个新元素作为head.next,也就是作为第一个元素?还是您走到列表的末尾并将其添加到那里?

【问题讨论】:

  • 你可以根据需要在开头、结尾甚至中间添加它。
  • 如果你提供了 add(Entry e) 功能。您通常会在哪里添加它?
  • 你可以在任何你想要的地方添加它。如果你只有一个指向列表第一个元素的指针(称为head),那么在开头添加一个新元素需要O(1),而在末尾插入它需要O(n),其中@ 987654323@是链表的大小。

标签: singly-linked-list


【解决方案1】:

根据斯坦福大学的this lecture(13:00 分钟后),将步行添加到列表的末尾并在那里添加新节点。这是代码的屏幕截图(C++)

lecture notes from UC Berkley (Java) 中,他们将其添加为第一项,但随后他们明确地将其称为 insertFront()

public class SList {
  private SListNode head;             // First node in list.
  private int size;                   // Number of items in list.

  public SList() {                    // Here's how to represent an empty list.
    head = null;
    size = 0;
  }

  public void insertFront(Object item) {
    head = new SListNode(item, head);
    size++;
  }
}

LinkedList class in java framework(这是双向链表)中,add表示添加到链表的末尾。因此,如果您添加 1,然后添加 2,然后添加 3,则 3 将是列表中的最后一项。

简而言之:除非明确称为 addFront(或类似名称),否则在 LinkedList 上添加意味着添加为最后一项。

【讨论】:

    【解决方案2】:

    任何一种方式都可以,但出于性能原因,通常首选在前面插入。

    插入一个新元素作为头部非常快,O(1),因为你只需要创建一个元素和一个指向旧头部的指针。

    在末尾插入意味着遍历列表以找到最后一个元素并更新它指向新元素的指针。这是 O(n)。

    您也可以通过跟踪列表的尾部并在末尾进行 O(1) 插入来交换存储时间。但是你得到的东西比单链表要复杂一些。

    通常符合条件

    当我说通常时,我指的是手工制作的单链表,尤其是用 C 语言编写的,可能适用于一些空间非常宝贵并且需要额外空间来存储尾部的嵌入式设备实在是太多了。

    对于像 Java 这样的通用语言,LinkedList 实现存储尾部,因此两个操作都是 O(1)。有趣的是,在 Java 案例中,List 的抽象接口只定义了一个追加到列表的操作。

    实现(伪 C 语言)

    假设我有一些列表,例如

    struct List {
        int data;
        List *next;
    };
    

    如果我想在开头插入,我会写

    List* insert(List *original_list, int data) {
        List* head = allocate new List(data, original_list);
        return head;
    }
    

    如果我想追加,我会写

    void append(List *original_list, int data) {
        List* new_tail = allocate new List(data, null);
        ptr = original_list
        while(ptr->next != null)
            ptr++
        ptr->next = new_tail;
    }
    

    【讨论】:

      【解决方案3】:

      正如@munk 所说,任何一种方式都是可能的。但是,插入的时间复杂度可能会因您使用的结构而异。让我更清楚。

      让我们使用 C 语言来使其简单明了。实现单链表的一种可能方法是:

      typedef struct node {
          int foo;
          node_t* next;
      } node_t;
      
      typedef struct list {
          node_t* head;
      } list_t;
      

      这样,您首先创建一个结构node 来存储您要存储的信息,然后声明第二个结构list,它只包含指向列表第一个节点的指针,即@987654324 @。有了这个实现:

      • 在开头插入需要O(1) 时间(您只需更改head 字段并使用next 进行一些调整。
      • 在末尾插入需要 O(n) 时间,因为您必须遍历整个列表。



      实现单链表的第二种方法是:

      typedef struct node {
          int foo;
          node_t* next;
      } node_t;
      
      typedef struct list {
          node_t* head;
          node_t* tail;
      } list_t;
      

      您维护一个指向列表的 last 元素的指针,这使得在末尾的插入也需要O(1) 时间。但是,这种实现比另一种占用更多的空间。

      【讨论】:

        猜你喜欢
        • 2014-10-12
        • 2014-12-27
        • 2023-02-10
        • 2020-01-31
        • 2020-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-04
        相关资源
        最近更新 更多