目录
- 单链表
1.1 无头单链表
1.2 有头单链表 - 单向循环链表
- 双链表
3.1 双链表
3.2 双向循环链表 - 总结与对比
一、单链表
1. 无头单链表(Headless Singly Linked List)
定义:链表无头结点,直接由头指针指向第一个数据节点。
特点:
- 插入/删除第一个节点需特殊处理。
- 空链表时头指针为
NULL
。
核心代码
typedef struct LNode {int data;struct LNode *next;
} LNode, *LinkList;bool InitList(LinkList *L) {*L = NULL;return true;
}bool insert_head(LinkList *L, LNode *new) {if (new == NULL) return false;new->next = *L;*L = new;return true;
}
示例操作
int main() {LinkList list;InitList(&list);LNode *node = newnode(11);insert_head(&list, node); // 头部插入// ... 其他操作return 0;
}
2. 有头单链表(Singly Linked List with Header)
定义:链表包含头结点,头指针始终指向头结点。
优点:
- 插入/删除第一个节点与普通节点操作统一。
- 空链表时头指针不为
NULL
,统一处理逻辑。
核心代码
bool InitList(LinkList *L) {*L = (LNode*)malloc(sizeof(LNode));(*L)->next = NULL;return true;
}bool insert_head(LinkList L, LNode *new) {new->next = L->next;L->next = new;return true;
}bool insert_tail(LinkList L, LNode *new) {LNode *p = L;while (p->next != NULL) p = p->next;p->next = new;return true;
}
示例操作
int main() {LinkList list;InitList(&list);LNode *node = newnode(11);insert_head(list, node); // 头部插入node = newnode(88);insert_tail(list, node); // 尾部插入// ... 其他操作return 0;
}
二、单向循环链表(Circular Linked List)
定义:链表最后一个节点的next
指向头结点,形成循环。
特点:
- 支持从任意节点开始遍历整个链表。
- 删除操作需注意头结点的特殊处理。
核心代码
bool InitList(DLinkList *L) {*L = (LNode*)malloc(sizeof(LNode));(*L)->next = *L;return true;
}bool insert_head(LinkList L, LNode *new) {new->next = L->next;L->next = new;return true;
}LNode* delete_tail(LinkList L) {LNode *p = L, *q = L->next;while (q->next != L) {p = q;q = q->next;}p->next = L;return q;
}
三、双链表(Doubly Linked List)
1. 双链表
定义:每个节点包含prev
和next
指针,支持双向遍历。
特点:
- 可高效实现插入/删除操作(需同时维护前后指针)。
- 需额外存储空间。
核心代码
typedef struct DNode {int data;struct DNode *prev, *next;
} DNode, *DLinkList;bool insert_head(DLinkList L, DNode *new) {new->next = L->next;new->prev = L;if (L->next != NULL) L->next->prev = new;L->next = new;return true;
}DNode* delete(DLinkList L, DNode *node) {if (node == L) return NULL;node->prev->next = node->next;if (node->next != NULL) node->next->prev = node->prev;return node;
}
2. 双向循环链表(Circular Doubly Linked List)
定义:双链表最后一个节点的next
指向头结点,头结点的prev
指向尾节点。
特点:
- 支持高效双向遍历和循环操作。
- 操作需处理循环指针。
核心代码
bool InitList(DLinkList *L) {*L = (DNode*)malloc(sizeof(DNode));(*L)->next = *L;(*L)->prev = *L;return true;
}bool insert_head(DLinkList L, DNode *new) {new->next = L->next;new->prev = L;L->next->prev = new;L->next = new;return true;
}DNode* delete_tail(DLinkList L) {DNode *p = L->prev;p->prev->next = L;L->prev = p->prev;return p;
}
四、总结与对比
结构类型 | 插入/删除时间复杂度 | 优点 | 缺点 |
---|---|---|---|
无头单链表 | O(n) | 简单 | 头部操作需特殊处理 |
有头单链表 | O(1)(头插) | 操作统一 | 需额外头结点空间 |
单向循环链表 | O(1)(头插) | 支持循环遍历 | 需处理循环指针 |
双链表 | O(1)(双向操作) | 支持双向遍历 | 空间占用更大 |
双向循环链表 | O(1)(双向操作) | 完全循环遍历 | 实现复杂度最高 |
关键点总结
- 头结点的作用:统一操作逻辑,避免空指针问题。
- 循环链表的优势:遍历无需判断尾节点,适合需要循环遍历的场景。
- 双链表的适用场景:需要频繁双向遍历或快速删除节点的场景(如浏览器历史记录)。