我的消除单链表最大重复元素序列的方法不行

问题描述 投票:0回答:1

这段代码应该在一个节点列表中搜索重复元素的最大序列,然后将其删除(每个节点只与下一个元素有连接,它是一个单向链表)。执行卡在列表的最后一个元素(未打印,我不明白为什么)并且代码永远不会完成(它永远不会打印最后一个“打印”)。我的代码确实正确计算了每个元素的位置但是它卡在最后一个上。在之前修改代码时,它要么没有消除最大的序列,要么删除了整个列表。

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”。

python algorithm nodes singly-linked-list
1个回答
0
投票

这条语句最终会在

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 上运行

© www.soinside.com 2019 - 2024. All rights reserved.