Search code examples
pythonpython-3.xlinked-list

For the following code in python, I am getting the error--AttributeError: 'str' object has no attribute 'next'


class Node:

    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedList:

    def __init__(self):
        self.head = None

    def printList(self):
        temp = self.head
        while(temp):
            print(temp.data)
            temp = temp.next

    def push(self, newData):
        newNode = Node(newData)
        newNode.next = self.head
        self.head = newNode

    def insertAfter(self, prevNode, newData):
        if prevNode is None:
            print("The given node must be in the linked list")
            return
        newNode = Node(newData)
        newNode.next = prevNode.next
        prevNode.next = newNode

    def append(self, newData):
        newNode = Node(newData)
        if self.head is None:
            self.head = newNode
            return
        last = self.head
        while(last.next):
            last = last.next
        last.next = newNode
    def deleteNode(self, key):
        temp = self.head
        if(temp is not None):
            if(temp.data == key):
                self.head = temp.next
                temp = None
                return
        while(temp is not None):
            if temp.data == key:
                break
            prev = temp
            temp = temp.next
        if(temp == None):
            return
        prev.next = temp.next
        temp = None

    def __repr__(self):
        return 'LinkedList(%s)' % str(self)

    def __iter__(self):
        current = self.head
        while current:
            yield current.data
            current = current.next

    def __str__(self):
        return '[%s]' % ', '.join([x for x in self])


if __name__ == '__main__':
    list = LinkedList()

    while True:
        print("1. Add an element")
        print("2. Delete an element")
        print("3. Push an element")
        print("4. Insert after an element")
        print("5. Print the list")
        menu = int(input("Choose an action: "))

        if menu == 1:
            data = input("Add an element: ")
            list.append(data)
        elif menu == 2:
            key = input("Add an existing element to delete: ")
            list.deleteNode(key)
        elif menu == 3:
            newData = input("Push an element: ")
            list.push(newData)
        elif menu == 4:
            prevNode = input("Add an element to insert after[Previous Node]: ")
            newData = input("Add an element to insert after[New Data]: ")
            list.insertAfter(prevNode,newData)
        elif menu == 5:
            print(list)
        else:
            print("Wrong input try again. ")

the error is coming from the insertAfter() when I start passing some values in list.insertAfter(prevNode, newData) but I couldn't figure out how the error occur.

sample inputs:
[godbless, iluvu, 69]

  1. Add an element
  2. Delete an element
  3. Push an element
  4. Insert after an element
  5. Print the list

Choose an action: 4

Add an element to insert after[Previous Node]: iluvu

Add an element to insert after[New Data]: enkk

Traceback (most recent call last): File "C:/Users/Admin/PycharmProjects/LinkedListIntro/IntroToLinkedList.py", line 94, in list.insertAfter(prevNode,newData) File "C:/Users/Admin/PycharmProjects/LinkedListIntro/IntroToLinkedList.py", line 29, in insertAfter newNode.next = prevNode.next AttributeError: 'str' object has no attribute 'next'


Solution

  • The issue is that you pass to insertAfter two data values, but insertAfter expects the first of those two to be a node instance, not a data value.

    So here is what you could do:

    Define a method find which will find a given data value in the list and will return the node that has it:

    def find(self, data):
        current = self.head
        while current:
            if current.data == data:
                return current
            current = current.next
    

    Now you can use this method in insertAfter:

    # The name of the argument changes:
    def insertAfter(self, prevData, newData):
        # Get the node where this data occurs:
        prevNode = self.find(prevData)
        if prevNode is None:
            print("The given node must be in the linked list")
            return
        newNode = Node(newData)
        newNode.next = prevNode.next
        prevNode.next = newNode
    

    It would be good to apply the same name change in the elif menu == 4 block, as the user inputs a value, not a node.