python - 如何将我的第一个节点的 prev 设置为我的最后一个节点的下一个以创建循环双向链表?
问题描述
我正在使用循环双向链表创建约瑟夫斯问题。我收到一个属性错误,我认为这是因为我的 current_node(第一个节点)还没有 .prev。
我知道我的第一个节点的 prev 应该指向我的最后一个节点的下一个以创建循环双向链表。
有人可以指导我是否正确识别错误?如果是,我该如何纠正?
如果不是,那么我可以纠正错误的其他方法是什么?
#Initialize the node
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
def remove(self, n):
print("Student " +str(n)+ " was removed")
class Circle:
# Initializing the DLL
def __init__(self):
self.head = None
self.tail = None
#Inserting elements 2 to n in the dll
def insert_after(self, x, data):
y = Student(data) # make a new Node object.
z = Student(data)
z = x.next
y.prev = x
y.next = z
x.next = y
z.prev = y
def josephus_solution(self, dllist, n, k):
no_of_active_nodes = n
current_node = Student(1)
#last_node = Student(n)
#print(current_node.prev)
for i in range(2, n + 1):
dllist.insert_after(current_node, i)
count = 0
#print(current_node.data)
while (current_node.next != current_node.prev):
#print(current_node.next.prev)
current_node = current_node.next
count += 1
#print(current_node.data)
if (count == k):
current_node.remove(current_node.data)
current_node.prev.next = current_node.next
current_node.next.prev = current_node.prev
count = 0
no_of_active_nodes -= 1
#print(no_of_active_nodes)
if (no_of_active_nodes == 1):
print("Student" + str(current_node.data) + "Recieves the scholarship")
return current_node.data
dllist = Circle()
n = 5 #int(input('Input number of people (n): '))
k = 2 #int(input('The nth person will be executed. Input k: '))
ans = dllist.josephus_solution(dllist, n, k)
错误
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/tmp/ipykernel_24/3762059582.py in <module>
54 n = 5 #int(input('Input number of people (n): '))
55 k = 2 #int(input('The nth person will be executed. Input k: '))
---> 56 ans = dllist.josephus_solution(dllist, n, k)
/tmp/ipykernel_24/3762059582.py in josephus_solution(self, dllist, n, k)
32 #print(current_node.prev)
33 for i in range(2, n + 1):
---> 34 dllist.insert_after(current_node, i)
35 count = 0
36 #print(current_node.data)
/tmp/ipykernel_24/3762059582.py in insert_after(self, x, data)
24 x.next = y
25
---> 26 z.prev = y
27
28 def josephus_solution(self, dllist, n, k):
AttributeError: 'NoneType' object has no attribute 'prev'
解决方案
错误的直接原因z
是None
,您的代码因此无法访问prev
该行中的任何属性z.prev = y
。原因是当第一个节点被创建时,它的prev
和next
属性被初始化为None
,并且当这个节点作为x
参数传递给 时insert_after
,然后z = x.next
一个None
值被分配给z
。
您的方法有几个问题:
insert_after
调用两次是没有意义的Student
,因为你想插入一个节点,而不是两个- 尽管您的
Circle
类具有 ahead
和 atail
属性,但它们在初始化为 之后从未使用过None
,因此 Circle 实例中实际上没有任何内容可以帮助您维护列表。Student
您不妨在类上定义所有方法。 - 中的while条件
josephus_solution
可能是为了测试列表中只剩下一个节点,但它实际上验证是否还剩下两个。诚然,当current_node
是刚刚被删除的节点,但是返回的数据是被删除节点的数据而不是剩余的活动节点,并且current_node
不是刚刚删除的节点时,这个条件会导致循环退出它仍然有两个活动节点。
其他一些评论:
- 当您
josephus_solution
作为方法调用时,不必也将实例作为参数传递。self
已经可用于该方法 - 我会将节点的创建拆分为一个单独的通用方法,并让我们
josephus_solution
处理现有的链表。 - 就像在循环列表中一样,任何
next
或prev
属性都不应该是None
,当将它们初始化为self
而不是None
. - 该
remove
方法不应该负责打印消息,但另一方面应该负责重新连接prev
和next
引用。无论如何,这个方法不需要获取参数,因为它通过self
. - 在原始约瑟夫斯问题中,第一个节点编号为 1,因此当 k=2 时,要删除的第一个节点是编号为 2 的节点。您的代码将首先删除编号为 3 的节点。要与原始问题保持一致,请移动该
current_node = current_node.next
语句将成为循环体中的最后一行。这也有助于确保在评估条件current_node
时它永远不是刚刚删除的节点。while
- 由于您的
while
条件已经考虑到何时停止,因此没有理由跟踪no_of_active_nodes
变量。
还有很多话要说,但我认为这些是最重要的。
考虑到上述所有因素,这是对您的代码的更正:
class Student:
def __init__(self, data):
self.data = data
# Better make prev/next self references to avoid None:
self.next = self
self.prev = self
def remove(self):
# Perform the remove here
self.prev.next = self.next
self.next.prev = self.prev
def insert(self, data):
# Should only create one node, not two
node = Student(data)
node.next = self
node.prev = self.prev
self.prev = node.prev.next = node
# Handy method to create a circular list from values
@classmethod
def fromiterator(cls, iterator):
head = cls(next(iterator))
for value in iterator:
head.insert(value)
return head
def josephus_solution(self, k):
count = 0
current_node = self
while current_node.next is not current_node: # This is how to test for 1 node
count += 1
if count == k:
current_node.remove() # No argument
print("Student " +str(current_node.data) + " was removed")
count = 0
current_node = current_node.next # do this at the end of the iteration
# No need to keep track of active nodes ...
return current_node
# These are the parameters of the "original" problem (see Wikipedia)
n = 41
k = 3
dllist = Student.fromiterator(iter(range(1, n+1)))
# Don't pass the list as argument: it already is available as `self`
dllist = dllist.josephus_solution(k)
# Perform output in the main code, not inside method
print("Student " + str(dllist.data) + " recieves the scholarship")
推荐阅读
- delphi - 外部延迟它在多线程中工作吗?
- swift - 使用 EarlGrey 2 在 UITableViewCell 中声明标签
- mysql - MySQL SELECT 从 2 个表中获取最新记录
- python - 使用 Swift 5.2 调用 REST API
- javascript - 使用那里已经存在的链接将属性添加到 ahref 按钮
- sql - SQL 窗口函数,用于获取存在超过 1 个唯一姓氏的地址(雪花)
- python - 从字符串中提取数字和浮点数
- php - 无法将隐藏值传递给 laravel 中的数据库
- javascript - 从 Python BeautifulSoup 中的 javascript 源中提取值
- javascript - 如果复选框为真,我如何使用 asyncstorage 存储?