python 链表定义(链表-中等)含源码(三十)
·
问题说明(含示例)
问题描述:设计并实现一个单链表的类 MyLinkedList,支持以下操作:
MyLinkedList():初始化链表。get(index):获取下标为index的节点值,若下标无效返回 -1。addAtHead(val):在链表头部插入值为val的节点。addAtTail(val):在链表尾部插入值为val的节点。addAtIndex(index, val):在下标为index的节点前插入值为val的节点(若index等于链表长度则追加到尾部,若index大于长度则不插入)。deleteAtIndex(index):若下标有效,删除下标为index的节点。
示例:输入操作序列:["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]输入参数:[[], [1], [3], [1, 2], [1], [1], [1]]
输出结果:[null, null, null, null, 2, null, 3]
解释:
- 初始化链表
myLinkedList。 - 头部插入 1 → 链表:
1。 - 尾部插入 3 → 链表:
1->3。 - 在 index=1 前插入 2 → 链表:
1->2->3。 - 获取 index=1 的值 → 返回 2。
- 删除 index=1 的节点 → 链表:
1->3。 - 获取 index=1 的值 → 返回 3。
解题关键
核心思路是基于单链表的节点结构,通过维护头节点和链表长度,实现各操作的逻辑,具体步骤:
- 节点定义:用
ListNode类表示节点,包含val(值)和next(指向下一节点的引用)。 - 链表初始化:维护
head(头节点)和length(链表长度),初始时head=None,length=0。 - get 操作:
- 先判断索引有效性(
0 ≤ index < length),无效返回 -1。 - 从 head 开始遍历
index次,定位到目标节点并返回其值。
- 先判断索引有效性(
- addAtHead 操作:
- 创建新节点,新节点的
next指向当前 head,再将 head 更新为新节点,长度 +1。
- 创建新节点,新节点的
- addAtTail 操作:
- 若链表为空,直接将新节点作为 head;否则遍历到最后一个节点,将其
next指向新节点,长度 +1。
- 若链表为空,直接将新节点作为 head;否则遍历到最后一个节点,将其
- addAtIndex 操作:
- 若索引无效(
index < 0 或 index > length),直接返回。 - 若索引为 0,复用
addAtHead;否则遍历到index-1节点,插入新节点(新节点next指向原index节点,index-1节点next指向新节点),长度 +1。
- 若索引无效(
- deleteAtIndex 操作:
- 若索引无效(
index < 0 或 index ≥ length),直接返回。 - 若索引为 0,将 head 更新为
head.next;否则遍历到index-1节点,将其next指向index节点的下一节点(跳过index节点),长度 -1。
- 若索引无效(
对应代码
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class MyLinkedList:
def __init__(self):
self.head = None
self.length = 0
def get(self, index: int) -> int:
if index < 0 or index >= self.length:
return -1
current = self.head
for _ in range(index):
current = current.next
return current.val
def addAtHead(self, val: int) -> None:
new_node = ListNode(val)
new_node.next = self.head
self.head = new_node
self.length += 1
def addAtTail(self, val: int) -> None:
new_node = ListNode(val)
if self.length == 0:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
self.length += 1
def addAtIndex(self, index: int, val: int) -> None:
if index < 0 or index > self.length:
return
if index == 0:
self.addAtHead(val)
else:
new_node = ListNode(val)
current = self.head
for _ in range(index - 1):
current = current.next
new_node.next = current.next
current.next = new_node
self.length += 1
def deleteAtIndex(self, index: int) -> None:
if index < 0 or index >= self.length:
return
if index == 0:
self.head = self.head.next
else:
current = self.head
for _ in range(index - 1):
current = current.next
current.next = current.next.next
self.length -= 1
对应的基础知识
实现该算法需掌握以下基础概念与操作:
- 单链表结构:由节点组成,每个节点包含数据和指向下一节点的引用,逻辑上连续但物理上非连续。
- 类与对象:用
ListNode类定义节点结构,MyLinkedList类封装链表操作,通过实例化对象管理链表。 - 引用与指针:Python 中通过变量引用节点对象,
next属性存储对下一节点的引用,实现节点间的连接。 - 循环遍历:通过
for或while循环移动节点引用(如current = current.next),实现对链表的访问。 - 边界条件处理:判断索引是否有效(如
index < 0或超出长度)、链表为空(head = None)等特殊情况。
对应的进阶知识
该问题的解决涉及数据结构与算法的进阶思想:
- 时间复杂度分析:
get、addAtIndex、deleteAtIndex需遍历到目标位置,时间复杂度为 O (n)(n 为链表长度)。addAtHead直接操作头节点,时间复杂度为 O (1);addAtTail在非空链表中需遍历到尾部,时间复杂度为 O (n)。
- 空间复杂度:所有操作仅使用常数级额外空间(存储节点引用和临时变量),空间复杂度为 O (1)。
- 数据结构选择:单链表适合频繁插入 / 删除操作(无需像数组那样移动元素),但随机访问效率较低(需从头遍历)。
- 状态一致性维护:通过
length变量实时记录链表长度,避免每次操作都遍历计数,优化效率;需确保length与实际节点数严格同步。
编程思维与启示
- 抽象数据结构实现:将链表的底层细节(节点连接)封装在类方法中,对外提供简洁接口(如
get、add),体现封装思想。 - 辅助变量的价值:
length变量看似简单,却能大幅简化索引有效性判断,避免冗余遍历,体现 “空间换时间” 的优化思路。 - 边界情况优先考虑:链表操作中,空链表、头节点、尾节点的处理是易错点,需优先设计这些场景的逻辑(如
addAtTail中先判断length == 0)。 - 引用操作的严谨性:单链表的核心是节点引用的修改(如
current.next = new_node),需明确变量指向的对象,避免因引用错误导致链表断裂(如deleteAtIndex中需修改前一节点的next,而非局部变量current)。
更多推荐


所有评论(0)