什么是链表
链表是一种动态数据结构,由一系列节点组成,每个节点包含:
- 数据 域 - 存储实际数据
- 指针 域 - 指向下一个节点的地址
链表 vs 数组
| 特性 | 数组 | 链表 |
|---|---|---|
| 内存分配 | 静态,编译时确定 | 动态,运行时申请 |
| 插入/删除效率 | 低(需移动元素) | 高(只需修改指针) |
| 内存使用 | 连续 | 可以不连续 |
| 访问方式 | 随机访问(O(1)) | 顺序访问(O(n)) |
基本结构
// 定义链表节点
struct Node {
int data; // 数据域
struct Node* next; // 指针域,指向下一个节点
};
链表类型
1. 单链表
typedef struct ListNode {
int val;
struct ListNode* next;
} ListNode;
2. 双链表
typedef struct DoublyListNode {
int val;
struct DoublyListNode* prev; // 指向前驱
struct DoublyListNode* next; // 指向后继
} DoublyListNode;
3. 循环链表
- 尾节点指向头节点
- 可以是单向或双向循环
基本操作示例
创建节点
ListNode* createNode(int value) {
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
newNode->val = value;
newNode->next = NULL;
return newNode;
}
插入节点
// 头部插入
void insertAtHead(ListNode** head, int value) {
ListNode* newNode = createNode(value);
newNode->next = *head;
*head = newNode;
}
// 尾部插入
void insertAtTail(ListNode** head, int value) {
ListNode* newNode = createNode(value);
if (*head == NULL) {
*head = newNode;
return;
}
ListNode* temp = *head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
删除节点
void deleteNode(ListNode** head, int value) {
if (*head == NULL) return;
// 如果要删除头节点
if ((*head)->val == value) {
ListNode* temp = *head;
*head = (*head)->next;
free(temp);
return;
}
// 查找要删除的节点
ListNode* current = *head;
while (current->next != NULL && current->next->val != value) {
current = current->next;
}
if (current->next != NULL) {
ListNode* temp = current->next;
current->next = current->next->next;
free(temp);
}
}
遍历链表
void printList(ListNode* head) {
ListNode* current = head;
while (current != NULL) {
printf("%d -> ", current->val);
current = current->next;
}
printf("NULL\n");
}
完整示例
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构
typedef struct Node {
int data;
struct Node* next;
} Node;
// 创建新节点
Node* createNode(int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 在链表末尾添加节点
void append(Node** head, int data) {
Node* newNode = createNode(data);
if (*head == NULL) {
*head = newNode;
return;
}
Node* temp = *head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
// 打印链表
void printList(Node* head) {
Node* current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
int main() {
Node* head = NULL;
// 创建链表: 1->2->3->NULL
append(&head, 1);
append(&head, 2);
append(&head, 3);
printf("链表内容: ");
printList(head);
return 0;
}
应用场景
- 实现栈、队列、哈希表等数据结构
- 动态内存管理
- 文件系统
- 浏览器历史记录
- 音乐播放列表
注意事项
- 注意内存泄漏,及时释放不再使用的节点
- 操作前检查空指针
- 双链表需要同时维护前驱和后继指针
- 循环链表要防止无限循环
链表是C语言中重要的数据结构,理解其原理和操作对于深入学习数据结构和算法很有帮助。
