还是上次的猴子问题,当时最后一个解法想到的就是通过为链表的方式,不过上次是用了列表做的一个伪链表,这次打算使用类来做一个伪链表。
首先建立一个类作为链表的一个节点,存有值和下一个节点的坐标。
class Node:
def __init__(self,value,next=None):
self.value = value
self.next = next
然后在建立一个伪链表类,里面要有链表的长度和头结点。
class Link:
def __init__(self,length):#这里需要给定一个初始长度,当然也可以默认为1
self.length = length
self.root = self.create_link()#建立链表的方法等会再写
通过初始化确定了表的长度,下面就是向这个链表里面加东西了,由于我这里本来打算是解决猴子出圈问题的(约瑟夫环)所以我默认的给每个节点赋予了代表其编号的初始值。
def create_link(self):
if self.length <= 0:
return False
if self.length ==1:
root = Node(1)
return root
else:
root = Node(1)
temp = root#用于存储临时量
for i in range(2,self.length+1):
#第n-1的节点的下一个节点为n节点
temp.next = Node(i)
#这里面的i是为了给猴子编号用,其实也可以为任意值或者说是[]。
temp = temp.next#同时将节点n给到临时储存
temp.next = root
#for循环走完了之后temp存着的就是最后一个节点,这是让最后一个节点的下一个只想头节点,使这个链表循环。
self.tail = temp#同时标记处尾节点
return root
其实有了这个就可以进行猴子问题的探讨了,但是当时我一时兴起有倒腾了一下链表的增删改查。
先说查,我们的每个节点存有两个值,一个是数值,一个是下一个节点的位置,所有第n个节点的位置,我们得去问第n-1个节点,以此类推,最后都要去问第一个节点(除了查找第一个节点),第一个节点的话就直接返回我们在初始化的时候标记的头结点(root),第一个以后的就用for循环来做。直接上代码:
def find_link(self,n):
if n == 1:
return self.root
else:
temp = self.root#中间过渡
for i in range(n-1):#为什么是n-1?试试看如果找第二个节点的时候需要循环几次就明白了
temp = temp.next
return temp
再说增,这里我们增加的话,我们需要两个值,一个是位置值,一个是该节点的数值。比如链表长是10的话,那么我们输入的位置值应该在什么样的范围?1-10应该没有争议,那么0,11,12行不行?
这里我们假设链表的第一个元素就是第一个而非下标0,那么插入0号位置就显得没有意义了,所以0排除。那么11呢?插入11号位置就是相当于在尾部追加一个元素,这是可以的,那么12呢?链表长就是10,突然插入一个12,也是没有意义的,当然要是较真的话可以说用空值(或者说默认值)占位11,然后在插入12号位。这个应该属于扩充链表长度的范畴了。
所以得把位置值限定在1-11 也就是 1到链表长度+1的范围。
那么要在第n个位置插入值v要如何实现呢?很简单,首先找到n-1的节点,因为他的next指向第n个节点,我们只用改变第n-1个节点的指向,同时让插入的那个元素指向原来的第n个节点就完事了!当然中间得使用temp来过度。对了别忘了给表长+1
对了,那如何找到第n-1个节点呢?参考上面的查。然后,上代码:
def insert_link(self,n,value):
if n <= 0 or n > self.length+1:#限制长度
return False
elif n ==1:#头结点处理,尾节点的next要指向新头节点,同时要标记新头节点
temp = self.tail
temp.next = Node(value)
temp.next.next = self.root
self.root = temp.next
self.length += 1
else:
self.length += 1
temp = self.root
for i in range(n-2):#寻找n-1个节点
temp = temp.next
t = temp.next#第n-1个节点储存的next
temp.next = Node(value)
if n == self.length:
self.tail = temp.next#重新标记尾节点
temp.next.next = t
删也是一样,要先找到n-1个节点,不过不同的是,只用将n-1节点的next指向n+1就完事了,不过要注意头结点和尾节点的重新标记,当然还要记得表长-1:
def del_link(self,n):
if n <= 0:
return False
n = n % self.length
if n ==0:
n = self.length
#上面是n>len导致循环的问题,可以忽略
if self.length == 1:
self.root.next = None
#表长为1在删除的话就是空表了
elif n == 1:#处理头结点标记
temp = self.root.next
self.tail.next = temp
self.root = self.tail.next
self.length -= 1
else:
if n == self.length:#处理尾节点标记,好吧其实可以用elif。。。。
self.tail = self.find_link(n-1)
self.tail.next = self.root
self.length -= 1
else:
temp = self.find_link(n-1)
temp.next = temp.next.next
self.length -= 1
改的话就没什么说的了,找到第n个然后改掉:
def change_link(self,n,value):
self.find_link(n).value = value
增删改查到这里就都写完了,不过有些地方需要改一下就是在搜索范围这块,仅仅是在增的时候有范围的限定,其他地方没有特意去做范围限定,修改之后的整体如下:
class Node:
def __init__(self,value,next=None):
self.value = value
self.next = next
class Link:
def __init__(self,length):
self.length = length
self.root = self.create_link()
def create_link(self):
if self.length <= 0:
return False
if self.length ==1:
root = Node(1)
return root
else:
root = Node(1)
temp = root
for i in range(2,self.length+1):
temp.next = Node(i)
temp = temp.next
temp.next = root
self.tail = temp
return root
def insert_link(self,n,value):
if n <= 0 or n > self.length+1:
return False
elif n ==1:
temp = self.tail
temp.next = Node(value)
temp.next.next = self.root
self.root = temp.next
self.length += 1
else:
self.length += 1
temp = self.root
for i in range(n-2):
temp = temp.next
t = temp.next
temp.next = Node(value)
if n == self.length:
self.tail = temp.next
temp.next.next = t
def del_link(self,n):
if n <= 0 or n >self.length:
return False
if self.length == 1:
self.root.next = None
elif n == 1:
temp = self.root.next
self.tail.next = temp
self.root = self.tail.next
self.length -= 1
else:
if n == self.length:
self.tail = self.find_link(n-1)
self.tail.next = self.root
self.length -= 1
else:
temp = self.find_link(n-1)
temp.next = temp.next.next
self.length -= 1
def change_link(self,n,value):
if n <= 0 or n >self.length:
return False
self.find_link(n).value = value
def find_link(self,n):
if n <= 0 or n >self.length:
return False
if n == 1:
return self.root
else:
temp = self.root
for i in range(n-1):
temp = temp.next
return temp
def show_link(self):#增加了显示全部的方法
temp = self.root
while True:
print(temp.value,end=' ')
temp = temp.next
if temp == None or temp == self.root:#碰到空或者碰到尾节点(下一个指向头节点的节点)
print()
break
折腾了半天不能忘记了初衷,解决猴子问题!
def king(n,m,k):
monkey = Link(n)
temp = monkey.root
while True:
for i in range(m-2):
temp = temp.next
temp.next = temp.next.next
#数到第m-1个 踢出m个
temp = temp.next
monkey.length -= 1#表长记得-1
if monkey.length == k:
for i in range(k):#循环打印剩余的猴子
print(temp.value)
temp = temp.next
break