简体   繁体   中英

How to implement insert method in a doubly linked list?

I need to implement this insert function in my doubly linked list and I'm having trouble getting it to properly insert elements at given indexes. I am able to add an element into an empty list object, but when I attempt to add a new node at the last node, I get an error saying:

'NoneType' object has no attribute 'setPrev'

I understand what this error means and have tried shifting my function around to avoid this error and get the right output, but to no avail.

Question: How can I fix this insert function in order to allow it to add nodes in all cases?

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

A testcase is the following scenario:

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)

output is as follows:

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

The problem is that n is a DLLNode you construct yourself. By default prev and next are set to Null ; therefore you cannot call any methods on them.

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

The last situation works as follows:

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

with C the current X the next of current and N the n (new node). First we set the (new node). First we set the prev and next of n`:

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

Now we check whether X actually is a real node (although this is strictly not necessary, since "last nodes" are handled above). If X is not None , we set the prev of X to N :

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

Finally we do not longer need C to point to X (otherwise we could not call functions of X ), so we set the next of C to N :

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

Can you provide test data to test if the implementation works correctly?

I believe the problem is here

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

When insert at the last element, you need to traverse to the current last element say last . Assume you did that you can do

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM