本篇从链表的任意位置删除元素开始讲述,前面相关操作可以看文末完整代码
任意位置删除元素
思路:
思路:
1、既然我们要删除任意位置,所需的参数肯定有:表示位置的location。
2、链表中删除,我们使用删除结点的前一个结点的next指向要删除的结点的后一个结点。
即要同时找到图中的q和location
伪代码如下:
找q部分:
q=head
i=i
while i<location-1:
q=q.next
i+=1
删除操作核心部分:
q.next=q.next.next
size-=1
最后考虑一下几个特殊点:
①删除位置是否合法:空表,删不了,location小于零或者大于元素个数,删不了
②单结点:因为无法进入循环也无法用q删除,所以我们直接调用写好的删头(尾)结点函数或者直接head=None
③删末尾元素:本情况已包含在代码里
④是否对size自减,while循环i是否自增?
那么我们直接上代码:
#任意位置删除
def del_anywhere(self,location):
if self.is_empty() or location<0 or location>self.size:
print('空表删不了哦')
elif self.size == 1 or location == 1:
self.head=None
self.size-=1
else:
q=self.head
i=1
while i<location-1:
q=q.next
i+=1
q.next=q.next.next
self.size-=1
测试案例以及结果如下:
按位置修改元素
思路:
1、我们需要什么参数?------------位置参数location你总得要吧,修改的新值value才能改吧
2、怎么修改?我们要找到location位置的结点,这时候需要它前一个结点的next指向才可以,所以又用到了我们的 q
3、找到q,修改即可
4、考虑一下特殊情况
伪代码如下:
找q部分:
q=head
i=i
while i<location-1:
q=q.next
i+=1
该值部分:
q.next.data=value
考虑特殊点:
①空表:改不了
②单结点:无法进入循环,直接head.data赋值
③删末尾元素:无特例
④size不用变,while的i记得自增
上代码:
#按位置修改值
def change_anywhere(self,location,value):
if self.is_empty():
print('空表无法修改元素')
elif self.size == 1:
self.head.data=value
else:
q=self.head
i=1
while i<location-1:
q=q.next
i+=1
q.next.data=value
测试案例以及结果:
按值修改元素(小细节很多建议反复看)🏆
思路:
1、既然是按值修改,那么就要遍历以获取有多少所匹配的元素
2、所需的参数为匹配的data值和要改的新data
3、遍历到底
4、空表无法修改
5、遍历完了我们需要知道是否改了值,那么可以再循环内加个 flag 记录
万事俱备,直接上伪代码:
遍历:
q=head
while q: #这里q到了最后一轮循环会指向None,自动退出循环
q=q.next
匹配旧值部分:
if q.data == old_value:
匹配成功赋新值:
q.data=new_value
记录遍历过程是否改了值:(细节部分)
flag=0
while .......:
if........:
..........
flag+=1
if flag=0:
没有改值
else:
改了flag次
上封装函数代码:
#按值修改
def change_value(self,old_value,new_value):
if self.is_empty():
print('空表修改不了哦')
return
q=self.head
flag=0
while q:
if q.data == old_value:
q.data=new_value
flag+=1
q=q.next
if flag == 0:
print('未匹配相关值,修改失败')
else:
print(f'修改了{flag}处')
测试以及结果:
按值查找返回位置(同样有很多细节)
分析:
①遍历链表,而且要遍历充分
②链表没有索引下标,所以要自己记录下标
③空表情况无法遍历
④可以用 flag 记录匹配成功次数,若为0记录为匹配失败
⑤设置一个 bag[ ] 列表用于存储可能有多个的下标,并且有返回值
伪代码如下:
遍历和记录: q=self.head flag bags i=1 while q: if q.data == value: bags追加i flag+=1 q=q.next i+=1 循环结束的判断匹配是否成功: if flag == 0: 查无此值 return [] else: 查到flag个值 return bags
上完整代码:
#按值返回位置
def return_index(self,value):
if self.is_empty():
print('空表无法操作')
return
q=self.head
flag=0
bags=[]
i=1
while q:
if q.data == value:
bags.append(i)
flag+=1
q=q.next
i+=1
if flag == 0:
print('查无此值')
return []
else:
print(f'查到{flag}个值')
return bags
结果如下:(查找值为20的位置)
返回了一个列表包含两个值
链表转置(用到了双指针)
不多说了,直接看分析:
为了编写一个反转链表的函数,我们可以保持您现有的链表类和节点类不变,并添加一个新的方法来执行反转操作。
反转链表的核心思想是迭代地遍历链表,同时改变每个节点的
next
指针,使其指向前一个节点
# 反转链表
def reverse(self):
prev = None
q = self.head
while q:
next_node = q.next # 保存对下一个节点的引用
q.next = prev # 反转当前节点的指针
prev = q # 移动 prev 指针到当前节点
q = next_node # 移动 q 指针到下一个节点
self.head = prev # 更新头节点为新的头节点(原来的尾节点)
def reverse(self): if self.is_empty() or self.size==1: return else: prev=None q=self.head while q: next_q=q.next q.next=prev #self.head=q 可在此处更新头结点为q(不过没必要),因为可在外部直接设置为prev(因为循环内部还未将prev更新为q) prev=q q=next_q self.head=prev #此位置为外部设置新头结点
注意标红处之所以我们可以直接放到循环外部,因为不论是内部还是外部该语句都是更新头结点,循环内部是不断一步步更新,放循环外部是一步更新头结点
结果如下:
方法二:
def reverse2(self):
if self.is_empty():
print('空表')
else:
q=self.head
self.head=None
while q:
self.add_head(q.data)
q=q.next
直接把头结点拿出来之后用q遍历每个结点进行头插即可
链表思维导图
完整代码&测试样例
#结点的类
class Node(object):
def __init__(self,data):
self.data=data
self.next=None
#链表类
class LinkList(object):
def __init__(self):
self.head=None
self.size=0
#判空
def is_empty(self):
return self.size == 0
#头插
def add_head(self,value):
node=Node(value)
node.next=self.head
self.head=node
self.size+=1
#遍历
def show_me(self):
if self.is_empty():
print('空链表,不用遍历')
return
else:
q=self.head
while q:
print(q.data,end=' ')
q=q.next
#尾插
def add_tail(self,value):
node=Node(value)
if self.is_empty():
self.head=node
self.size+=1
else:
p=self.head
while p.next:
p=p.next
p.next=node
self.size+=1
#任意位置插入
def add_anywhere(self,location,value):
node = Node(value)
if location>self.size+1 or location<=0:
print('插入位置有误')
return
else:
r = self.head
#第一个位置就头插
if location == 1:
self.add_head(value)
else:
i=1
while i<location-1:
r = r.next
i+=1
node.next = r.next
r.next = node
self.size += 1
#头删
def del_head(self):
if self.is_empty():
print('删不了一点')
return
self.head=self.head.next
self.size-=1
#尾删
def del_tail(self):
if self.is_empty(): #空表删不了
print('删不了哦')
elif self.size == 1: #一个元素直接让self.head = None
self.head = None
self.size -= 1
else:
p = self.head
while p.next.next: #遍历到倒数第二个结点,
#如果这种方式理解不了可以用 i=1 while i<self.size-1 然后内部i+=1 也可以
p = p.next
p.next = None
self.size -= 1
#任意位置删除
def del_anywhere(self,location):
if self.is_empty():
print('空表删不了哦')
elif self.size == 1:
self.head=None
else:
q=self.head
i=1
while i<location-1:
q=q.next
i+=1
q.next=q.next.next
self.size-=1
#按位置修改值
def change_anywhere(self,location,value):
if self.is_empty():
print('空表无法修改元素')
elif self.size == 1:
self.head.data=value
else:
q=self.head
i=1
while i<location-1:
q=q.next
i+=1
q.next.data=value
#按值修改
def change_value(self,old_value,new_value):
if self.is_empty():
print('空表修改不了哦')
return
q=self.head
flag=0
while q:
if q.data == old_value:
q.data=new_value
flag+=1
q=q.next
if flag == 0:
print('未匹配相关值,修改失败')
else:
print(f'修改了{flag}处')
#按值返回位置
def return_index(self,value):
if self.is_empty():
print('空表无法操作')
return
q=self.head
flag=0
bags=[]
i=1
while q:
if q.data == value:
bags.append(i)
flag+=1
q=q.next
i+=1
if flag == 0:
print('查无此值')
return []
else:
print(f'查到{flag}个值')
return bags
# 反转链表
def reverse(self):
prev = None
q = self.head
while q:
next_node = q.next # 保存对下一个节点的引用
q.next = prev # 反转当前节点的指针
prev = q # 移动 prev 指针到当前节点
q = next_node # 移动 q 指针到下一个节点
self.head = prev # 更新头节点为新的头节点(原来的尾节点)
if __name__ =='__main__':
new_l=LinkList()
print('头插')
new_l.add_head(10)
new_l.add_head(20)
new_l.add_head(30)
new_l.show_me()
print()
print('尾插')
new_l.add_tail(10)
new_l.add_tail(20)
new_l.add_tail(40)
new_l.show_me()
print()
print('任意位置')
new_l.add_anywhere(6,30)
new_l.show_me()
print()
print('任意位置(尾部)')
new_l.add_anywhere(8,50)
new_l.show_me()
print()
print('任意位置(头部)')
new_l.add_anywhere(1,0)
new_l.show_me()
print()
print('头删')
new_l.del_head()
new_l.show_me()
print()
print('尾删')
new_l.del_tail()
new_l.show_me()
print()
print('任意位置删(这里删的10)')
new_l.del_anywhere(4)
new_l.show_me()
print()
print('任意位置该元素')
new_l.change_anywhere(3,1)
new_l.show_me()
print()
print('按值修改')
new_l.change_value(1,666)
new_l.show_me()
print()
print('查下标')
print(new_l.return_index(20))
print('反转链表前')
new_l.show_me()
print()
# 反转链表
new_l.reverse()
print('反转链表后')
new_l.show_me()
print()