链表(Linked List)详解
基本概念
链表是一种线性数据结构,由一系列节点(Node)组成,每个节点包含:
- 数据域:存储实际数据
- 指针域:存储指向下一个节点的地址
与数组的连续存储不同,链表的节点在内存中是非连续存储的,通过指针链接在一起。
单链表(Singly Linked List)特点
- 单向链接:每个节点只有一个指针指向后继节点
- 头指针:指向链表中的第一个节点
- 尾节点:最后一个节点的指针指向
nullptr
- 时间复杂度:
- 插入/删除:O(1)(已知位置时)
- 随机访问:O(n)
- 查找:O(n)
C++ 单链表完整实现
#include <iostream>
using namespace std;
// 链表节点类
class Node {
public:
int data; // 数据域
Node* next; // 指向下一节点的指针
Node(int val) : data(val), next(nullptr) {}
};
// 单链表类
class LinkedList {
private:
Node* head; // 头指针
public:
// 构造函数:初始化空链表
LinkedList() : head(nullptr) {}
// 析构函数:释放所有节点内存
~LinkedList() {
Node* current = head;
while (current) {
Node* next = current->next;
delete current;
current = next;
}
head = nullptr;
}
// 在头部插入新节点
void insertAtHead(int val) {
Node* newNode = new Node(val);
newNode->next = head;
head = newNode;
}
// 在尾部插入新节点
void insertAtTail(int val) {
Node* newNode = new Node(val);
if (!head) {
head = newNode;
return;
}
Node* current = head;
while (current->next) {
current = current->next;
}
current->next = newNode;
}
// 在指定位置插入节点
void insertAtIndex(int index, int val) {
if (index < 0) return;
if (index == 0) {
insertAtHead(val);
return;
}
Node* newNode = new Node(val);
Node* current = head;
// 移动到插入位置的前一个节点
for (int i = 0; i < index - 1 && current; ++i) {
current = current->next;
}
if (!current) return; // 索引超出范围
newNode->next = current->next;
current->next = newNode;
}
// 删除指定值的节点
void deleteByValue(int val) {
if (!head) return;
if (head->data == val) {
Node* temp = head;
head = head->next;
delete temp;
return;
}
Node* current = head;
while (current->next) {
if (current->next->data == val) {
Node* temp = current->next;
current->next = temp->next;
delete temp;
return;
}
current = current->next;
}
}
// 删除指定位置的节点
void deleteByIndex(int index) {
if (!head || index < 0) return;
if (index == 0) {
Node* temp = head;
head = head->next;
delete temp;
return;
}
Node* current = head;
for (int i = 0; i < index - 1 && current; ++i) {
current = current->next;
}
if (!current || !current->next) return;
Node* temp = current->next;
current->next = temp->next;
delete temp;
}
// 查找节点是否存在
bool contains(int val) {
Node* current = head;
while (current) {
if (current->data == val) return true;
current = current->next;
}
return false;
}
// 反转链表(经典面试题)
void reverse() {
Node* prev = nullptr;
Node* current = head;
Node* next = nullptr;
while (current) {
next = current->next; // 保存下一节点
current->next = prev; // 反转指针
prev = current; // 前移prev
current = next; // 前移current
}
head = prev; // 新头节点
}
// 打印链表
void display() {
Node* current = head;
while (current) {
cout << current->data;
if (current->next) cout << " -> ";
current = current->next;
}
cout << " -> nullptr" << endl;
}
};
// 测试用例
int main() {
LinkedList list;
cout << "插入节点测试:" << endl;
list.insertAtTail(1);
list.insertAtTail(2);
list.insertAtHead(0);
list.insertAtIndex(2, 99);
list.display(); // 0 -> 1 -> 99 -> 2 -> nullptr
cout << "\n删除节点测试:" << endl;
list.deleteByValue(99);
list.deleteByIndex(0);
list.display(); // 1 -> 2 -> nullptr
cout << "\n反转链表测试:" << endl;
list.insertAtHead(3);
list.reverse();
list.display(); // 2 -> 1 -> 3 -> nullptr
cout << "\n查找测试:" << endl;
cout << "Contains 1: " << boolalpha << list.contains(1) << endl; // true
cout << "Contains 5: " << boolalpha << list.contains(5) << endl; // false
return 0;
}
关键操作解析
-
头插法:
newNode->next = head; head = newNode;
-
尾插法:
while (current->next) current = current->next; // 定位尾节点 current->next = newNode;
-
反转链表:
// 三指针法: while (current) { next = current->next; // 保存下一节点 current->next = prev; // 指针转向 prev = current; // 前移prev current = next; // 前移current } head = prev; // 更新头指针
-
内存管理:
- 构造函数初始化头指针为
nullptr
- 析构函数遍历释放所有节点内存
- 删除节点时注意更新指针关系
- 构造函数初始化头指针为
应用场景
- 需要频繁插入/删除的场景
- 实现栈、队列等数据结构
- 动态内存分配(操作系统内存管理)
- 音乐/视频播放列表
- 浏览器历史记录管理
注意:单链表的变体还有双向链表(双指针)和循环链表(尾节点指向头节点),在不同场景下各有优势。