这段代码应该在一个节点列表中搜索重复元素的最大序列,然后将其删除(每个节点只与下一个元素有连接,它是一个单向链表)。执行卡在列表的最后一个元素(未打印,我不明白为什么)并且代码永远不会完成(它永远不会打印最后一个“打印”)。我的代码确实正确计算了每个元素的位置但是它卡在最后一个上。在之前修改代码时,它要么没有消除最大的序列,要么删除了整个列表。
from slistH import SList
from slistH import SNode
import sys
class SList2(SList):
def delLargestSeq(self):
# implement here your solution
previous_to_seq = self._head # we start at the first position for all pointers
first_after_sequence = self._head
a = 0 # this variable controls that it has been the first time that a condition has been fulfilled
first = 0 # this variable controls the position of the first element o a sequence
pointer2 = self._head
pointer = self._head
new_pointer = self._head # this pointer will store the node that is the most repeated
count = 0 # this is a counter, it will calculate the position that is currently being analyzed
last = 0 # this variable stores the position of the last element of a sequence
prev_first = 0 # stores the biggest sequence's first element position (until a bigger one is detected)
prev_last = 0 # stores the biggest sequence's last element position (until a bigger one is detected)
while pointer is not None: # it will be repeated until the end of the list (None) is detected
if a == 0 : # if the elements are equal and in sequence
if pointer.elem == pointer.next.elem:
last = count + 1 # there is one more element in the sequence, it will be the last one counted at that moment
else:
if (last - first) >= (prev_last - prev_first): # if a bigger sequence is detected...
prev_first = first # this will be now the first position of the biggest sequence
prev_last = last # this will be now the last position of the biggest sequence
new_pointer = pointer # this will now be the most repeated element
first = last + 1 # the next element will be the first of the next sequence that we will compare
last = first
print(f"{pointer.elem} || {count} ") # these are just to observe that everything is working
pointer = pointer.next # this moves the pointer through the list
count += 1 # +1 position displacement of the pointer
if pointer is None:
a = 1
for i in range(prev_last): # goes through the list until the biggest sequence's last element's position
if pointer2.next.elem == new_pointer.elem: # if the next element is part of the sequence...
if a == 1: # if it is the first element of the sequence...
previous_to_seq = pointer2 # it is the first element before the biggest sequence
a = 2 # this ensures that it is the first time that this has been executed
elif a == 2 and pointer2.next.elem != new_pointer.elem: # if they are not the first element before sequence
first_after_sequence = pointer2.next # first element different from the ones in the sequence after it
a = 3 # ensures it is executed only once
pointer2 = pointer2.next
if previous_to_seq.elem == new_pointer.elem: # in case there is no element before the sequence
previous_to_seq = previous_to_seq.next
previous_to_seq.next = first_after_sequence
print(f"first after sequence: {first_after_sequence.elem}")
print(f"last before sequence {previous_to_seq.elem}")
nodes_list = SList2()
for i in (1, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6):
nodes_list.addLast(i)
print(nodes_list)
nodes_list.delLargestSeq()
print(f"{nodes_list} || final list")
执行卡在列表的最后一个元素(未打印,我不明白为什么)并且代码永远不会完成(它永远不会打印最后一个“打印”)。我的代码确实正确计算了每个元素的位置但它卡在了最后一个。在之前修改代码时,它要么没有消除最大的序列,要么删除了整个列表。我也有一个问题,循环到达“无”并且无没有“.next”。
这条语句最终会在
pointer
是列表中的最后一个节点时运行:
if pointer.elem == pointer.next.elem:
此时
pointer.next
是None
,所以pointer.next.elem
是无效引用,会产生错误。
其他备注:
你有太多的评论只是陈述显而易见的。评论不应将声明翻译成英文,而应给出更高层次的含义。如果没有这样的意思,那就不要加评论了
命名很重要,可以使代码更具可读性(无需注释每一行)。例如,
a
是一个不好的名字,它应该表示 “......这是第一次满足条件”.
在第一个循环中,变量
a
只有在循环即将退出时才会更新,所以这意味着第一个循环永远不会执行else
块,也永远不会更新first
的值
算法过于依赖positions。在链表中,您不需要跟踪位置(索引),而是nodes。索引是您在使用本机列表时通常会使用的索引,而不是链接列表。跟踪节点引用的优点是您不需要第二个循环来执行实际删除。在链表中,删除只能通过 one 赋值来完成。
对于必须在列表的最start 发生删除的情况,您的代码中没有规定,因为在这种情况下,应该更新
_head
参考,但在您的实施中没有这样的声明.
还有更多问题,但我认为这足以解释为什么算法不起作用。
我在下面添加了一个实现,但我不得不做出一些在您的问题中没有阐明的假设:
如果一个(非空)列表没有两个具有相等值的连续节点,那么具有重复值的最长序列将是 1。因为这不是真正可以称为“重复”的东西,我假设在这种情况下,列表应该保持原样,没有任何删除。
如果列表中有两个或多个具有 same 长度的重复部分,并且这些部分恰好是最长的,则只会删除节点的第一部分。
创建辅助节点就OK了,可以用
SNode(None)
创建。由于您没有提供SNode
实现,我只能猜测可以这样调用构造函数。
要从链表中删除一个部分,您可以更好地跟踪前面该部分的节点,因为那个节点需要更新其
next
属性。
重复的第一部分可能出现在列表的最开头,然后就没有这样的前导节点。在那种情况下,我们有一个不同的情况,列表的
_head
属性应该更新(如果它恰好是最长的重复系列)。
为了允许以相同的方式处理这些不同的场景,通常的做法是创建一个在列表的头节点之前添加前缀的虚拟节点。那么第一个系列的前驱节点就是那个虚拟节点,如果需要删除该部分,我们可以更新前驱的
next
属性,而无需采取任何特别的预防措施。最后,我们可以将 dummy.next
分配回 _head
属性,这将在相关时正确更新头部。
def delLargestSeq(self):
# Create a dummy node in front of the list, as this facilitates the rest
# of the code, and makes it easy to update the head at the end of the process
dummy = SNode(None)
dummy.next = self._head
# For efficient removal, we should keep track of the node that *precedes*
# the first node to remove
beforeDupes = dummy
beforeFirstToRemove = lastToRemove = None
numNodesToRemove = 1
while beforeDupes.next:
endDupes = beforeDupes.next
numNodes = 1
# Extend the selection of nodes for as long as they have the same value
while endDupes.next and endDupes.next.elem == endDupes.elem:
numNodes += 1
endDupes = endDupes.next
# Keep track of the longest sequence
if numNodes > numNodesToRemove:
numNodesToRemove = numNodes
beforeFirstToRemove = beforeDupes
lastToRemove = endDupes
beforeDupes = endDupes
# Assuming that a removal must concern at least 2 nodes,
# as a single node cannot be called "duplicate"
if numNodesToRemove > 1:
# Remove the longest sequence of duplicates
beforeFirstToRemove.next = lastToRemove.next
# If the sequence started at the first node, the head reference must be updated
self._head = dummy.next
看到它在 repl.it 上运行