【问题标题】:How to implement insert method in a doubly linked list?如何在双向链表中实现插入方法?
【发布时间】:2015-10-07 23:18:06
【问题描述】:

我需要在我的双向链表中实现这个insert 函数,但我无法让它在给定索引处正确插入元素。我可以将一个元素添加到一个空列表对象中,但是当我尝试在最后一个节点添加一个新节点时,我收到一条错误消息:

“NoneType”对象没有属性“setPrev”

我了解此错误的含义,并尝试改变我的功能以避免此错误并获得正确的输出,但无济于事。

问题:如何修复此插入功能以使其在所有情况下都可以添加节点?

class DLLNode:
    def __init__(self,initdata):
        self.data = initdata
        self.next = None
        self.prev = None

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

    def getData(self):
        return self.data

    def getNext(self):
        return self.next

    def getPrev(self):
        return self.prev

    def setData(self, new_data):
        self.data = new_data

    def setNext(self, new_next):
        self.next = new_next

    def setPrev(self, new_prev):
        self.prev = new_prev

class DLL:
    """ Class representing a doubly-linked list. """

    def __init__(self):
        """ Constructs an empty doubly-linked list. """
        self.head = None
        self.size = 0

    def __str__(self):
        """ Converts the list into a string representation. """
        current = self.head
        rep = ""
        while current != None:
            rep += str(current) + " "
            current = current.getNext()

        return rep

    def isEmpty(self):
        """ Checks if the doubly-linked list is empty. """
        return self.size <= 0

    def insert(self, item, index):
        """ Inserts a node at the specified index. """
        # Construct node.
        current = self.head
        n = DLLNode(item)

        # Check index bounds.
        if index > self.size:
            return 'index out of range'

        # If the list is empty...
        if self.isEmpty():
            self.head = n
            self.head.setPrev(self.head)

        # If the index is the first node...
        if index == 0:
            n.setNext(self.head)
            self.head = n
            if self.size == 0:
                self.prev = n
        # If the index is the last node...
        elif index == self.size:
            n.next.setPrev(n)

        # If the index is any other node...
        else:
            if current == None:
                n.setPrev(self.prev)
                self.prev.setNext(n)
                self.prev = n
            else:
                n.setNext(current)
                n.getPrev().setNext(n)
                current.setPrev(n.getPrev())
                n.setPrev(n)

        self.size += 1

测试用例是以下场景:

l = DLL()
l.insert(88, 0)
l.insert(99, 1)
l.insert(77, 2)
l.insert(55, 3)
l.insert(34, 1)
l.insert(3, 0)
l.insert(15, 6)
l.insert(100, 8)
print("list after inserts", l)

输出如下:

Index out of range.
list after inserts 3 88 34 99 77 55 15 """

【问题讨论】:

  • 看起来最后一种情况可能也被错误地实现了......
  • @CommuSoft,你有没有看到什么让你跳出来的东西,我可以做些什么来修复我的功能?
  • 查看答案。但是我没有(直接)方法来测试实现是否完全正确,你能提供测试用例吗(edit你的答案)
  • 为什么要使用带有索引的链表?这有点违反直觉。通常,向链表中的插入要么在任何一端起作用,要么根据排序顺序插入。维护链表的索引对我来说似乎很奇怪。

标签: python algorithm list class insert


【解决方案1】:

问题在于n 是您自己构建的DLLNode。默认prevnext设置为Null;因此你不能对它们调用任何方法。

def insert(self, item, index):
    """ Inserts a node at the specified index. """
    # Construct node.
    current = self.head
    n = DLLNode(item)

    # Check index bounds.
    if index > self.size:
        return 'index out of range'

    # If the list is empty...
    if self.isEmpty():
        self.head = n
        self.head.setPrev(self.head)
    else : #added else case to prevent overlap
        for x in range(0,index-1): #Obtain the current
            current = current.next #move to the next item
        # If the index is the first node...
        if index == 0:
            n.setNext(self.head)
            self.head = n
            if self.size == 0:
                self.prev = n
        # If the index is the last node...
        elif index == self.size:
            current.setNext(n) #set n to be the next of current
            n.setPrev(current) #set current to be the previous of n

        # If the index is any other node...
        else:
            n.setNext(current.next)
            n.setPrev(current)
            if current.next != None :
                current.next.setPrev(n)
            current.setNext(n)

    self.size += 1

最后一种情况如下:

 /------\|
C    N   X
|\------/

CcurrentXthenextofcurrentandNthen(new node). First we set theprevandnextofn`:

 /------\|
C <--N-->X
|\------/

现在我们检查X 是否真的是一个真实的节点(尽管这不是必需的,因为上面处理了“最后一个节点”)。如果X不是None,我们将Xprev设置为N

 /------\|
C <--N-->X
     |\-/

最后我们不再需要C指向X(否则我们无法调用X的函数),所以我们将Cnext设置为N

 /--\|
C <--N-->X
     |\-/

能否提供测试数据来测试实现是否正确?

【讨论】:

  • 测试数据为: l = DLL() l.insert(88, 0) l.insert(99, 1) l.insert(77, 2) l.insert(55, 3 ) l.insert(34, 1) l.insert(3, 0) l.insert(15, 6) l.insert(100, 8) print("插入后的列表", l) """输出如下: 索引超出范围。插入后的列表 3 88 34 99 77 55 15 """
  • 我得到的输出是这个“插入 3 后的列表”。所以由于某种原因,它只在索引 0 处添加三个?你认为为什么会这样?
  • @Jason:有一个小的 by-1 错误;现在修好了。测试用例工作正常。
  • 总是那么小,不是吗? :-) 再次感谢!这真的帮助了我,我非常感谢你向我解释它实际上是如何与图表一起工作的。
【解决方案2】:

我相信问题就在这里

elif index == self.size:
    n.next.setPrev(n)

在最后一个元素插入时,需要遍历到当前的最后一个元素,比如last。假设你做到了,你可以做到

elif index == self.size:
    last.setNext(n)
    n.setPrev(last)
    n.setNext(head) #only if this list is also circular
    self.size++

【讨论】:

  • 另外一个问题是dll没有last(如果有,该方法肯定无法更新last)。
猜你喜欢
  • 1970-01-01
  • 2022-11-16
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
  • 2019-11-23
  • 1970-01-01
  • 1970-01-01
  • 2012-02-18
相关资源
最近更新 更多