单链表设计
题中已经给了要实现的方法和每个方法的具体功能
- 设计时创建一个虚拟节点self.dummy指向头节点,会减少边界问题
- 题目中也没有求给链表设置头节点、尾节点,所以整个程序中都不设置头节点、尾节点,否则每次增删都要考虑头尾节点是否发生变化,会增加很多代码
- 由于addAtIndex、deleteAtIndex方法实现时要判断传入的index是否有效,所以实例初始化时加个self.size 会让这两个方法实现起来更方便
- 额外加个traverse方法,打印遍历链表,方便调试
- 先实现addAtHead、addAtTail,再实现get,最后实现addAtIndex、deleteAtIndex
class Node:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class MyLinkedList:
def __init__(self):
"""只需要设置这两个必须字段,有了self.dummy每次遍历从虚拟节点开始遍历,不需要头节点,因为虚拟节点指向的就是头节点
设置的变量属性越少,代码问题就越少"""
self.dummy = Node() # 设置一个虚拟头节点
self.size = 0 # 记录当前节点数量,因为addAtIndex、deleteAtIndex都需要判断当前节点数量
def get(self, index: int) -> int:
"""获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。"""
# 判断下标是否有效
if index >= self.size:
return -1
# [1,2,3] index=2
cur = self.dummy
for _ in range(index+1):
cur = cur.next
return cur.val
def addAtHead(self, val: int) -> None:
"""将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。"""
# 创建一个node指向原本self.dummy的下一个节点,然后让self.dummy指向该节点
new_node = Node(val, self.dummy.next)
self.dummy.next = new_node
self.size += 1
def addAtTail(self, val: int) -> None:
""" 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。"""
# 遍历链表 到最后一个节点,设置next为new_node
new_node = Node(val)
# 遍历的时候弄个临时指针,如果用self.dummy循环,那就会导致self.dummy最终指向最后一个节点,而self.dummy应该是不变的
cur = self.dummy
while cur.next:
cur = cur.next
cur.next = new_node
self.size += 1
def addAtIndex(self, index: int, val: int) -> None:
"""将一个值为 val 的节点插入到链表中下标为 index 的节点之前。
如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。
如果 index 比长度更大,该节点将 不会插入 到链表中。"""
# 先判断index和链表长度的关系
if index > self.size:
return
elif index == self.size:
self.addAtTail(val)
return
# 当index < size,遍历链表,将一个值为 val 的节点插入到链表中下标为 index 的节点之前
# 需要找到前一个节点pre_node, 新节点next指向pre_node.next,pre_node.next指向新节点
pre_node = self.dummy
for _ in range(index): # [1,2,3] index=2
pre_node = pre_node.next
new_node = Node(val, pre_node.next) # 这里不需要判断pre_node.next是否为空等边界条件,是因为方法最开头就做了长度判断
pre_node.next = new_node
self.size += 1
def deleteAtIndex(self, index: int) -> None:
"""如果下标有效,则删除链表中下标为 index 的节点。"""
# 先判断下标是否有效
if index >= self.size:
return
# 当index < size,遍历链表,将pre_node的next指向pre_node.next.next
pre_node = self.dummy
for _ in range(index): # [1,2,3] index=0
pre_node = pre_node.next
pre_node.next = pre_node.next.next # 这里不需要判断pre_node.next是否为空,是因为方法最开头就做了长度判断,代码走到这里一定有pre_node.next
self.size -= 1
def traverse(self):
"""遍历链表"""
result = []
cur = self.dummy
while cur.next:
cur = cur.next
result.append(cur.val)
print(result)
# Your MyLinkedList object will be instantiated and called as such:
obj = MyLinkedList()
obj.addAtHead(7)
obj.addAtHead(2)
obj.addAtHead(1) # [1 2 7]
obj.traverse()
obj.addAtIndex(3,0) # [1 2 7 0 ]
obj.traverse()
obj.deleteAtIndex(2) # [1 2 0 ]
obj.traverse()
obj.addAtHead(6) # [6 1 2 0 ]
obj.traverse()
obj.addAtTail(4) # [6 1 2 0 4]
obj.traverse()
obj.addAtHead(4)
obj.addAtIndex(5,0)
obj.addAtHead(6) # [6 4 6 1 2 0 0 4]
obj.traverse()