在双向链表中,addLast方法只在链表为空时起作用一次,其他情况下根本不起作用

编程语言 2026-07-11

我需要为一个项目创建一个双向链表,它应该具备一个addFirst方法,用来在链表开头前置一个元素,以及一个addLast方法,将其追加到链表末尾。addFirst方法看起来工作正常,但addLast只有在链表为空时才起作用。如果链表中已经有至少一个节点,它就不会再添加。

class DoublyLinkedList(LinkedList):
    def __init__(self):
        LinkedList.__init__(self)
        self.tail = None

    def addLast(self, item):
        newNode = Node(item)        # make the given value a node
        newNode.prev = self.tail    # point the new node to the tail of the list
        if self.head is None:       # if it is an empty list just make it the head
            self.head = newNode
        self.tail = newNode         # the tail is now the new node
        self.count += 1             # num of items in the list is updated

    def addFirst(self, item):
        newNode = Node(item)        # make the given value a node
        newNode.next = self.head    # point new node to the head of the list
        """ if self.head is None:   # this part is commented out bc it was redundant
            self.head = newNode """ 
        self.head = newNode         # make the new node the head
        self.count += 1             # num of items in list is updated

下面是它继承自的链表类

class LinkedList():
    """Linked List class implementation"""

    def __init__(self): #Create a linked list
        self.head = None
        self.count = 0

    def is_empty(self): #Is the list empty?
        return self.head is None

    def size(self): #Size of the list
        return self.count

    def __len__(self): #Size of the list
        return self.count

    def __str__(self): #List as a stringE
        list_str = "["
        current = self.head

        while current:
            list_str += str(current)
            if current.next:
                list_str += ", "
            current = current.next
        list_str += "]"
        return list_str

    def add(self, value): #Add a new node
        newNode = Node(value)
        newNode.next = self.head
        if self.count == 0:
            self.tail = newNode
        self.head = newNode
        self.count = self.count + 1

    def append(self, value):
        curr = self.tail
        while curr.next:
            curr = curr.next
        newNode = Node(value)
        curr.next = newNode
        self.count += 1

    def remove(self, value): #Remove a node with a specific value
        curr = self.head
        prev = None
        while curr:
            if curr.data == value:
                if prev is None:
                   self.head = curr.next
                else:
                   prev.next = curr.next
                self.count = self.count -1 #self.count -= 1
                return
            prev = curr
            curr = curr.next
        raise ValueError(f"{value} is not in the list")

    def search(self, value): #Search for a node with a specific value
        curr = self.head

        while curr:
            if curr == value:
                return True
            curr = curr.next

        return False

以及我的节点类,方便参考

class Node: #a node of a linked list

    def __init__(self, node_data): #create new node
        self.data = node_data
        self.next = None
        self.prev = None

    def __str__(self): #overloads string operator
        return str(self.data)

我真的束手无策,调试似乎确实表明问题在于addLast结束时根本没有向列表添加值,因为查看打印方法时,节点的值显示为None。看起来尝试给尾部赋值的任何操作都不会被加入。据我所知,头指针和尾指针在初始时都应为None,它们的行为应该相同。

编辑:打印尾部时发现我添加的值确实在那里,所以我认为问题出在字符串化的方法,而不是尾部。

我在网上也查了很多,但我看到的每一个链表示例似乎都与我要用的实现不同。如果能想到其他选项我就不会来问这里,所以如果需要我再提供更多信息,请告诉我,因为我之前从未在这里提问过。

解决方案

有几个问题。

首先,你的双向链表的 addLast 方法并没有将尾节点的 next 属性设置为指向新创建的节点。它只设置了一个 prev 属性,从未设置 next

你可能以为继承关系会处理这件事,但基类 LinkedListappend 方法和 add 方法都从未被调用。

其次,若你确实调用了基类的方法,仍然会有问题,因为 append 方法不会更新 self.tail 的值,因此 self.tail 并不能保证指向尾节点。

我猜你希望 LinkedList 代码处理 next 属性,而 DoublyLinkedList 代码处理 prev 属性。因此你需要先修正 append 方法中的错误。举例来说,可以这样:

    def append(self, value):
        if self.count == 0:
            return self.add(value)
        # by definition the tail has its next attribute set to None (no loop needed)
        self.tail.next = Node(value)
        self.tail = self.tail.next  # update the reference to the tail
        self.count += 1

DoublyLinkedList 类中,依赖上述代码的方法可以通过在 addLast 方法中调用它来实现。可能长成这样:

    def addLast(self, item):
        prev_tail = self.tail
        super().append(item)        # apply the logic from base class
        self.tail.prev = prev_tail

你的 addFirst 也存在类似的问题,因为它只设置 next 属性,而没有设置 prev 属性。你不会在把列表转成字符串时注意到这一点——因为那只是依赖 next 属性——但 prev 属性将无法正确设置。下面给出一种可能的修正方式:

    def addFirst(self, item):
        super().add(item)           # apply the logic from base class
        if self.head.next:
            self.head.next.prev = self.head

其他备注

  • 避免在循环中用 += 构造字符串:每次迭代都会创建一个新字符串。
  • 两个类在向列表添加值的方法上应使用相同的名称:这样用户就不会误把单向链表的方法用于双向链表。
  • 定义 __iter__,这对其他方法(包括 __str__)有用。
  • 允许构造函数接收一些值来初始化链表。
  • 将对 next(和 prev)的操作集中在一个方法中,所有其他逻辑都依赖它:这样在实现双向链表时,基本上只需要覆盖一个方法。
  • 我建议将链表设计成循环的,甚至引入一个哨兵节点(哨兵),这通常会让代码更简洁一些。这些改动只是类内部实现,不必影响用户要使用的接口。
  • 你的代码中没有任何方法能够体现双向链表的优势。在你提供的实现里,双向链表只是增加了对 prev 的管理开销,没有带来任何好处。因此我建议添加一些在双向链表中更有效的方法,例如 __reversed__
  • 如果不打算让用户直接使用你的类的属性,或许可以在链表属性前加上前缀 _

下面演示一个可行的做法:

from typing import override

class LinkedList():
    class Node:  # A node of a singly linked list
        def __init__(self, value, nxt=None):
            self.data = value
            self.makeneighbors(nxt or self)

        # Override this method when needing a doubly linked list
        def makeneighbors(self, nxt):
            self.next = nxt

        def addafter(self, value):
            # Create a node of the same type and link it 
            self.makeneighbors(type(self)(value, self.next))

        def removenext(self):
            self.makeneighbors(self.next.next)

        def __str__(self):
            return str(self.data)


    def __init__(self, *init_data):
        self._sentinel = self.Node(None)
        self._count = 0
        for data in init_data:
            self.addlast(data)

    def isempty(self):
        return not self._count

    def size(self):
        return self._count

    def __len__(self):
        return self._count

    def _iterprevnodes(self):
        node = self._sentinel
        while node.next != self._sentinel:
            yield node
            node = node.next

    def __iter__(self):
        return (node.next.data for node in self._iterprevnodes())

    def __str__(self):
        return str(list(self))

    def addfirst(self, data):
        self._sentinel.addafter(data)
        self._count += 1

    def addlast(self, data):
        self._sentinel.data = data
        self.addfirst(None)
        self._sentinel = self._sentinel.next

    def remove(self, data):
        prevnode = next((node for node in self._iterprevnodes() if node.next.data == data), None)
        if not prevnode:
            raise ValueError(f"{data} is not in the list")
        prevnode.removenext()
        self._count -= 1


class DoublyLinkedList(LinkedList):
    class Node(LinkedList.Node): # A node of a doubly linked list, overriding behaviour
        @override
        def makeneighbors(self, nxt):
            super().makeneighbors(nxt)
            nxt.prev = self

    # Define some methods for which a doubly linked list is better suited
    def _iternodesreversed(self):
        node = self._sentinel.prev
        while node != self._sentinel:
            yield node
            node = node.prev

    def __reversed__(self):
        return (node.data for node in self._iternodesreversed())
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章