数组与线性结构

链表

链表把元素分别装在一个个叫节点的小盒子里,散落在内存各处。每个节点存一个值和一个指针(链接),指向下一个节点;最后一个节点指向空。可以想象成寻宝:每条线索只告诉你下一条在哪儿。要找到第五个元素,你得顺着四个链接走过去——没法直接跳。

这种布局把数组的取舍整个反了过来。由于元素并不连续,第 i 个元素没有现成的计算公式,所以定位到第 i 位或查找某个值都是 O(n)——你得沿着链子走。但如果你手里已经握着某个节点,把新节点接进去或把一个节点摘出来只是几次指针重连:在已知位置插入/删除是 O(1),不必挪动任何元素。在头部插入正是经典的 O(1) 操作。

单链表只向前链接;双链表还保存一个 prev 指针,于是你能双向行走,并在仅给出某节点时以 O(1) 删除它。代价是每个元素多花的内存(那些指针),以及糟糕的缓存表现——因为顺链跳转会在内存里东奔西跑,而不是在一整块里整齐前进。

struct Node { int v; Node* next; };
// head -> [10|*] -> [20|*] -> [30|/]  (/ = nullptr)
Node* push_front(Node* head, int x) {
    Node* n = new Node{x, head};  // point new node at old head
    return n;                     // O(1): no shifting
}
int nth(Node* head, int i) {      // O(n): must walk the chain
    while (i-- && head) head = head->next;
    return head ? head->v : -1;
}

在头部插入是 O(1);查找第 i 个值是 O(n)。

数组与链表是教科书式的取舍:数组胜在随机访问,链表胜在你已握住位置时的插入/删除。

又称
singly linked listdoubly linked list链表单链表双链表鏈結串列鏈表連結串列