单链表
一、单链表定义
以下为自己总结
链表中有多个节点,节点中存有数据、下个节点的地址,如果没有下个节点,则地址为空
链表如果要查看下一个节点,只能从节点存储的地址访问下一个节点,相当于python中的线性代码,只能从上往下运行,节点类似,只能从头开始,不能从中间、末尾开始
节点:
链表形式:
class Node:
def __init__(self, val):
# val 数据
self.val = val
# next 指指向下个节点的地址
self.next = None
单链表的操作
下面图中的p都指游标
1. 创建一个单链表类
class SingleLinkList:
def __init__(self, node: Node = None):
self.__head = node
定义链表最初指向的地址:self.__head,默认为None ,文章后面用head表示
2. 判断链表是否为空
返回布尔值
def is_empty(self) -> bool:
return self.__head is None
链表内有节点,则返回False,为空链表,则返回True
3. 返回链表长度
定义长度变量为0
定义一个游标cur代表指向链表的位置
当游标目前不为空,则cur=cur.next,游标指向下一个节点,长度+1
为空后,说明已经是最后一个节点
最后返回长度count
def length(self) -> int:
count = 0
cur = self.__head
while cur:
cur = cur.next
count += 1
return count
4. 遍历整个链表
既然都能获取链表长度,那么也可以遍历链表了
def travel_yield(self) -> Iterator:
cur = self.__head
while cur:
yield cur.val
cur = cur.next
5. 在链表头部添加数据
开始的时候,p的位置在链表的第一个节点,要在在第一个节点之前插入,
- 先把添加的数据定义node=Node(val),
- 然后node指向链表的第一个地址,即p:node.next = self.__head
- 再把p指向node:self.__head = node
def add(self, val) -> None:
node = Node(val)
node.next = self.__head
self.__head = node
6. 链表尾部添加数据
- 定义节点:node = Node(val)
- 插入尾部,有两种情况,一种是链表为空,另一种是已经有链表
2.1 链表不为空
创建一个游标cur,当cur.next不为空时cur = cur.next,为空则说明这是最后一个节点
然后定义cur.next = node
2.2 链表为空
空链表,则直接指向node
代码如下
def append(self, val) -> None:
node = Node(val)
if not self.is_empty():
cur = self.__head
while cur.next:
cur = cur.next
cur.next = node
else:
self.__head = node
7. 在指定位置添加元素
在指定位置添加元素需要传入添加元素的位置,即下标index,以及添加的数据val,有三种情况需要考虑
- index比链表长度大,以及index小于0
此时需要处理并报错 - index为0
即相当于在链表头部添加元素 - index等于链表长度
即相当于在链表尾部添加元素 - index在链表中间
下方讲述的是情况4:
假设index=5
- 先定义节点:node = Node(val),游标、节点个数count,可以理解为游标位置的下标
- 因为游标如果移动到了5的位置,那么,就无法操作下标4,
因此,移动游标的循环条件应该为count<index-1 - 当移动到4后node.next指向原下标5的位置,即node.next = cur.next
- 之后再把cur.next指向node
def insert(self, index: int, val) -> None:
length = self.length()
if index < 0 or index > length:
raise IndexError('超出链表长度范围')
elif index == 0:
self.add(val)
elif index == length:
self.append(val)
else:
node = Node(val)
count = 0
cur = self.__head
while count < index - 1:
count += 1
cur = cur.next
node.next = cur.next
cur.next = node
8. 删除链表中节点
节点位置有三中地方
- 链表开头
- 链表中间
- 链表尾部
有两种方法删除节点,第一种是创建一个游标,第二种是创建两个游标
8.1 创建一个游标删除节点
- 删除节点在链表开头
如果head.val等于val,那么就说明,删除节点是在链表开头
那么直接使head指向cur.next即可 - 删除节点在链表中间
利用cur.next.val和val对比,将游标移动到要删除节点的前一个位置
cur.next指向cur.next.next(当前游标位置的下下一个节点)
- 删除节点在链表尾部
链表尾部和链表中间一致,cur.next指向了要删除的节点,cur.next.next指向了要删除节点的后面,即尾部,那么指向的就是None
代码如下
def remove(self, val) -> None:
cur = self.__head
if self.__head.val == val:
self.__head = cur.next
else:
while cur.next:
if cur.next.val == val:
if cur != self.__head:
cur.next = cur.next.next
else:
self.__head = cur.next
break
else:
cur = cur.next
8.2 创建两个游标删除节点
创建两个游标cur§,pre(p1),其中,pre=None
- 删除节点在链表中间
两个游标位置如图:
当cur.val 不等于val时,pre.next指向cur,cur指向cur.next - 删除节点在链表头部
当cur.val 等于val时,如果cur等于head,那么,head就指向cur.next即可 - 删除节点在链表尾部
链表尾部和链表中间一致,pre.next指向了要删除的节点,cur.next指向了尾部的指向地址None,那么pre.next=cur.next
代码如下:
cur = self.__head
pre = None
while cur:
if cur.val == val:
if cur != self.__head:
pre.next = cur.next
else:
self.__head = cur.next
break
else:
pre = cur
cur = cur.next
三、整体代码
class Node:
def __init__(self, val):
self.val = val
self.next = None
class SingleLinkList:
def __init__(self, node: Node = None):
self.__head = node
def is_empty(self) -> bool:
return self.__head is None
def length(self) -> int:
count = 0
cur = self.__head
while cur:
cur = cur.next
count += 1
return count
def travel_yield(self) -> Iterator:
cur = self.__head
while cur:
yield cur.val
cur = cur.next
def add(self, val) -> None:
node = Node(val)
node.next = self.__head
self.__head = node
def append(self, val) -> None:
node = Node(val)
if not self.is_empty():
cur = self.__head
while cur.next:
cur = cur.next
cur.next = node
else:
self.__head = node
def insert(self, index: int, val) -> None:
length = self.length()
if index < 0 or index > length:
raise IndexError('超出链表长度范围')
elif index == 0:
self.add(val)
elif index == length:
self.append(val)
else:
node = Node(val)
count = 0
cur = self.__head
while count < index - 1:
count += 1
cur = cur.next
node.next = cur.next
cur.next = node
def remove(self, val) -> None:
cur = self.__head
pre = None
while cur:
if cur.val == val:
if cur != self.__head:
pre.next = cur.next
else:
self.__head = cur.next
break
else:
pre = cur
cur = cur.next