1. 设计链表的核心思路与实现解析
今天我想和大家分享力扣707题"设计链表"的解题过程。这道题看似基础,但涉及链表操作的多个关键细节,特别适合用来检验对数据结构的理解是否扎实。题目要求我们实现一个单链表,支持五种基本操作:获取指定位置节点值、在头部插入节点、在尾部插入节点、在指定位置插入节点以及删除指定位置节点。
在开始编码前,我们需要明确几个关键设计点。首先是虚拟头节点的使用——这是简化链表操作的重要技巧。虚拟头节点(dummy head)不存储实际数据,它的next指针始终指向真正的第一个节点。这种设计使得对头节点的操作(如插入或删除)与其他位置的操作保持一致,避免了特殊情况的处理。
其次是链表长度的维护。我们需要一个size变量来实时记录链表中有效节点的数量,这对边界条件判断至关重要。例如当index等于size时,表示在链表末尾追加节点;当index大于等于size时,则属于非法操作。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 链表类的设计与初始化
2.1 链表节点结构定义
首先定义链表节点的结构体,这是链表的基础构建块:
cpp复制struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
每个节点包含两个成员:
- val:存储节点的值
- next:指向下一个节点的指针
构造函数将val初始化为传入的值x,并将next指针设为nullptr(C++11中的空指针表示法),确保新节点默认不指向任何其他节点。
2.2 链表类的基本框架
链表类的主体框架如下:
cpp复制class MyLinkedList {
private:
ListNode* dummyHead; // 虚拟头节点
int size; // 链表长度
public:
MyLinkedList(); // 构造函数
int get(int index); // 获取节点值
void addAtHead(int val); // 头部插入
void addAtTail(int val); // 尾部插入
void addAtIndex(int index, int val); // 指定位置插入
void deleteAtIndex(int index); // 删除节点
};
这里使用了private修饰符封装内部实现细节,只对外暴露必要的操作接口。这是面向对象设计中重要的封装原则——隐藏实现细节,只暴露必要的公共接口。
3. 构造函数与初始化细节
3.1 构造函数的实现
cpp复制MyLinkedList::MyLinkedList() {
dummyHead = new ListNode(0); // 创建虚拟头节点,值任意(这里设为0)
size = 0; // 初始长度为0
}
构造函数完成了两个关键初始化:
- 创建虚拟头节点:这个节点的值不重要(这里设为0),它的存在只是为了简化操作
- 将size初始化为0:表示链表初始为空,不包含任何实际数据节点
注
