I've implemented a backwards linked list successfully, but I'm trying to find out how to implement a forwards linked list, and I can't seem to figure out how to do it. The problem is in my insert method. I'm trying to keep track of the previous node, and point it to the newly created node, but I'm missing something.
class Node(object):
def __init__(self, data=None, next_node=None):
self.data = data
self.next_node = next_node
def set_next(self, new_next):
self.next_node = new_next
def get_data(self):
return self.data
def get_next(self):
return self.next_node
class LinkedList(object):
def __init__(self, head=None):
self.head = head
def insert(self, data):
previous_node = self.head
current_node = self.head
new_node = Node(data)
if previous_node is not None:
previous_node.set_next(new_node)
previous_node = self.head
It's not clear what your insert method is supposed to do. If it is meant to insert at the beginning of the list (before head), then you should be setting new_node.set_next(previous_node) and self.head = new_node. If you meant to append to the end of the list, then you will need to scan through the list until you find the node with current_node.get_next() == None and do current_node.set_next(new_node).
Since this looks like homework, I don't want to straight out give you the answer. I will provide some pseudocode to get you started though
def insert(value):
let current = head
until current.next_node == None:
let current = current.next_node
let current.next_node = Node2(value)
Try this.
If the list is empty, set the head, and return. Else, loop "forward" through all the elements until you hit a None node. Once you do, set the appropriate next_node value.
class LinkedList(object):
def __init__(self, head=None):
self.head = head
def empty(self):
return self.head is None
def insert(self, data):
new_node = Node(data) # Want to insert this
if self.empty(): # Is this list empty?
self.head = new_node # Yes? Then add the head
else: # No? There are elements in the list
current_node = self.head # Save a moving reference
while not current_node.get_next() is None: # While there are forward nodes
current_node = current_node.get_next() # Move the reference forward
current_node.set_next(new_node) # Set the last node, thus inserting at the "end"
Let's write out what this does:
def insert(self, data):
previous_node = self.head # set to head of list
current_node = self.head # not used elsewhere
new_node = Node(data) # make a new node with the given data.
if previous_node is not None: # if the list isn't empty
previous_node.set_next(new_node) # point the list head to the new node
previous_node = self.head # does nothing; this was already the list head
Bottom line: this creates a new node and makes it the "next" node of the list head. That's all this does; your list will never be more than 2 nodes long. In fact, your list can't ever get a first node, because you have no code to insert into an empty list.
To fix this, you need a clear, adaptable algorithm, such as:
Create a new node.
Link the existing list behind the new node:
Set new.next to the current head node.
Point the list head to the new node.
Note that this works even with an empty list.
If you want a list that adds to the end, then also maintain a self.tail attribute that points to the last node in the list. Then your insert (append) looks like this:
Create a new node.
Link the new node to the existing tail:
if tail exists:
Set tail.next to the new node.
else:
Set head to the new node
Set tail to the new node.
Is this clear enough to implement?
Related
I need to add a node at the start of the circular linked list
I can add the node if the list is empty and I add every node using the function but if the list already has nodes then the function doesn't work
class Node:
def __init__(self,data):
self.data = data
self.ref = None
class CircularLinkedList:
def __init__(self):
self.head = None
self.tail = None
def atStart(self,newData):
newNode = Node(newData)
if self.head is None:
self.head = newNode
self.tail = newNode
self.tail.ref = newNode
if self.tail:
newNode.ref = self.tail.ref
self.tail.ref = newNode
def printList(self):
if self.head is None:
print("Circular linked list is empty")
n = self.head
while n:
print(n.data)
n = n.ref
if n == self.head:
break
cll = CircularLinkedList()
cll.head = Node("Monday")
e2 = Node("Tuesday")
e3 = Node("Wednesday")
cll.head.ref = e2
e2.ref = e3
e3.ref = cll.head
cll.atStart("Sunday")
cll.atStart("Monday")
cll.printList()
I need to change the head node using the atStart function and print the whole list but it prints the three nodes I have made (cll.head,e2,e3) or just the newNode using the atStart if list is empty
I tried debugging and seems like whenever the list is not empty it only takes the newNode data and doesnt set the ref of it head node and just prints the old three nodes
There are a few issues:
In atStart the if self.tail: condition will always be true. This is problematic, as only one of the two alternatives should be executed, not both. Yet when the first block executes (the case where the list was empty), self.tail gets a value, so this second if block will also execute (the case where the list is not empty). This should not be an if, but just a plain else: -- you want to cover all remaining cases (where the list was not empty).
In the case the list was not empty, the atStart method does not make the new node the head of the list, so the list becomes inconsistent.
The main program should not tinker with the head or ref attributes -- this should be left to the class code only. This leads to all kinds of problems. In this case the problem is that cll.tail remains None, and so the list is inconsistent and you cannot rely on the correct execution of the atStart method, because that assumes that tail was set correctly. You could add cll.tail = e3 to fix that particular issue, but again, this is bad practice. The logic for attaching nodes to eachother should be performed within the class code only.
Not a problem, but it is overkill for a circular list to have two node references (head and tail): in a non-empty list the head always follows the tail node, so there really is no need to remember what the head is when you have the tail. In short: just keep track of the tail.
Here is the adapted code:
class Node:
def __init__(self,data):
self.data = data
self.ref = None
class CircularLinkedList:
def __init__(self):
# No need for a head reference, as it is always coming after the tail
self.tail = None
def atStart(self,newData):
newNode = Node(newData)
if self.tail is None:
self.tail = newNode
else: # Must be ELSE to avoid executing both blocks
newNode.ref = self.tail.ref
self.tail.ref = newNode # new node always becomes the head
def printList(self):
if self.tail is None:
print("Circular linked list is empty")
n = self.tail.ref
while n:
print(n.data)
if n == self.tail:
break
n = n.ref
The main program corrected:
cll = CircularLinkedList()
# Don't alter the atttributes of the linked list or its nodes! Only use methods:
cll.atStart("Wednesday")
cll.atStart("Tuesday")
cll.atStart("Monday")
cll.printList()
print("----")
cll.atStart("Sunday")
cll.atStart("Monday")
cll.printList()
From www.geeksforgeeks.org:
The circular linked list is a linked list where all nodes are
connected to form a circle. In a circular linked list, the first node
and the last node are connected to each other which forms a circle.
There is no NULL at the end.
def atStart(self,newData):
if self.head is None:
# Initialize head and tail
newNode = Node(newData)
self.head = newNode
self.tail = newNode
else:
# Copy the old head node
old_head = self.head
# Make a new head node
self.head = Node(newData)
# Update the reference of the new head node to point the old_head
self.head.ref = old_head
# Now update the tail ref to point to the head (circular)
self.tail.ref = self.head
Explanation:
In this code if head and tail are empty, for the the first call of atStart method the head and tail will be the same, that's self.head is self.tail which evaluates to True. It's possible to implement this code a better way, where for example __init__ or atStart methods should except two values instead of one to initialize the head and tail together. Because in this way, the data of the head will reside in the tail uselessly even after adding a new head. If you call this:
cll.head.data == cll.tail.data
Now it's interesting what you will get. The first call to atStart method will evaluate to True, the second call may not evaluate to true. That's, whatever the first cll.head.data held will be there in cll.tail.data always. Effectively we're wasting cll.tail.data.
A better approach would be
def atStart(self, *newData):
if self.head is None:
# Initialize head and tail (each with its own data)
self.head = Node(newData[0])
self.tail = Node(newData[1])
# tail references head (circular)
self.tail.ref = self.head
#rest of code from above....
The second call to the atStart method will update the head of the circular list to point to the new head node (created to add the last value) and the tail reference will be updated to point back to the new head. Note that the ref attribute of the new head will be updated to reference the old head, it's a very important step or you will end up losing your old data.
This is a code to add a new node at the beginning of a linked list and then print the elements in the linked list. But when I run the program I get the following error in the last line when I call the ll1.print_LL() function:
AttributeError: 'NoneType' object has no attribute 'data'
And here is my code:
class Node:
def __init__(self, data):
self.data = data
self.ref = None
class LL:
def __init__(self):
self.head = None
def print_LL(self):
if self.head is None:
print("LL is empty")
else:
node = self.head
while self.head is not None:
print(node.data)
node = node.ref
def add_begin(self, data):
new_node = Node(data)
new_node.ref = self.head
self.head = new_node
ll1 = LL()
ll1.add_begin(10)
ll1.add_begin(20)
ll1.print_LL()
I have seen a post about a similar error on StackOverflow, but I'm still confused.
Why am I getting this error in my code and how do I fix it?
Short Answer:
Change while self.head is not None:
to
while node is not None:
Explanation*
The error message tells you something that you might think of. It tells you that at some point you're trying to get ".data" from a None variable, which means your loops at "some point" reach None.
Now, the issue is at this part
def print_LL(self):
if self.head is None:
print("LL is empty")
else:
node = self.head
while self.head is not None:
print(node.data)
node = node.ref
Here, you are assigning node = self.head which is making the pointer point to the first element (the head), and you WANT to make the pointer move forward, which what you're doing when you said: node=node.ref, however, your test condition is not correct, because you're testing against self.head.
Since self.head is never gonna be None, it will keep looping forever, but the node will keep moving forward and return a None error because there are no more nodes.
The answer:
Change the while loop to:
def print_LL(self):
if self.head is None:
print("LL is empty")
else:
node = self.head
while node is not None:
print(node.data)
node = node.ref
While the breaking error has been pointed out in the answer, there is another intricacy worth considering, add_begin() function should be changed to:
def add_begin(self,data):
new_node = Node(data)
if self.head is None:
self.head = new_node
else:
new_node.ref = self.head
self.head = new_node
.because when the first time you call add_begin() function, there is no value in head and as such the line
new_node.ref = self.head is meaningless as it is assigning None value to None value.
Also it improves code readability.
I'm asked what the effect of self.head, self.tail = self.tail, self.head is on a doubly linked list.
If I implement this code, the list now only consists of the last item added.
# Represent a node of doubly linked list
class Node:
def __init__(self, data):
self.data = data;
self.previous = None;
self.next = None;
class DoublyLinkedList:
# Represent the head and tail of the doubly linked list
def __init__(self):
self.head = None;
self.tail = None;
# addNode() will add a node to the list
def addNode(self, data):
# Create a new node
newNode = Node(data);
# If list is empty
if (self.head == None):
# Both head and tail will point to newNode
self.head = self.tail = newNode;
# head's previous will point to None
self.head.previous = None;
# tail's next will point to None, as it is the last node of the list
self.tail.next = None;
else:
# newNode will be added after tail such that tail's next will point to newNode
self.tail.next = newNode;
# newNode's previous will point to tail
newNode.previous = self.tail;
# newNode will become new tail
self.tail = newNode;
# As it is last node, tail's next will point to None
self.tail.next = None;
# display() will print out the nodes of the list
def display(self):
# Node current will point to head
current = self.head;
if (self.head == None):
print("List is empty");
return;
print("Nodes of doubly linked list: ");
while (current != None):
# Prints each node by incrementing pointer.
print(current.data),;
current = current.next;
def weird_line(self):
self.head, self.tail = self.tail, self.head
dList = DoublyLinkedList();
# Add nodes to the list
dList.addNode(1);
dList.addNode(2);
dList.addNode(3);
dList.addNode(4);
dList.addNode(5);
dList.weird_line();
dList.display();
OUTPUT: 5
source: https://www.javatpoint.com/python-program-to-create-and-display-a-doubly-linked-list
However, my professor is letting me choose out of four options:
The list will show up in reverse.
The list will be empty
The second half of the list will be deleted
The first half of the list will be deleted
I'm pretty sure, that my initial answer is correct.
Is there someone that could argue that one of the possible answers he gave me could be correct?
From what you have presented, you are right that the final display call will print the value of the node that was last added.
None of the four given options is true.
We can make some other remarks:
This swap of head and tail will make the list inconsistent, as you would expect the following to be always true:
head or head.previous is None
tail or tail.next is None
In a non-emtpy list, if you start with the head node, and follow the next references until a node's next attribute is None, you'll end up at the tail node.
In a non-emtpy list, if you start with the tail node, and follow the previous references until a node's previous attribute is None, you'll end up at the head node.
All these invariants will be violated if you call weird_line on a list with at least 2 nodes.
I'm trying to convert a string into a doubly linked list. I want to be able to traverse it, find a match, and then insert another linked list at a certain position. However, I'm having trouble with my pointers. I have 'current.prev', 'current', and 'current.next' pointers that should all be pointing at the nodes in that order. Instead, my .prev and current pointers always point to the same thing. I need to be able to point at the different parts of the linked list, otherwise I won't be able to traverse back to a certain spot so I can insert a new linked list.
this is the code that creates doubly linked lists for me:
#-----------------------doubly-linked-lists-----------------------#
class NodeD:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
class DoublyLL:
def __init__(self):
self.head = None
def append(self, new_data):
new_node = NodeD(new_data)
if self.head is None:
self.head = new_node
return
last = self.head
while last.next:
last = last.next
last.next = new_node
new_node.prev = last
return
def printList(self, node):
while node:
print(node.data, end=""),
last = node
node = node.next
this is the code that makes a string into a linked list:
#making-linked-lists-from-strings#
def dnaToLL(dnainput):
dnaLL = DoublyLL()
head = NodeD(dnainput[0])
dnaLL.head = head
current = dnaLL.head
for i in range(1, len(dnainput)):
current.prev = current
current = current.next
current.next = NodeD(dnainput[i])
return dnaLL
I've been using this to test where the pointers are pointing:
dnaLL = dnaToLL(DNA)
dnaLL = dnaLL.head
print(dnaLL.prev.data +dnaLL.data+dnaLL.next.data)
but with this input:
S1 = "neho"
DNA = "imfinehowru"
I get this output:
iim
any idea where I've gone wrong? I am assuming it's where I've tried to make strings into doubly linked lists, but any other order that I put the pointers in gives me errors.
Thank you for your help!
The problem is that whe you do current.prev = current, you're saying "the previous node is the current node" - not the actual previous node.
Keep in mind that the first node in the list should have .prev = None. You'd only want to set .prev for future nodes. This modification should fix your dnaToLL() function:
def dnaToLL(dnainput):
dnaLL = DoublyLL()
head = NodeD(dnainput[0])
dnaLL.head = head
current = dnaLL.head
for i in range(1, len(dnainput)):
# note how the order is changed
current.next = NodeD(dnainput[i])
current.next.prev = current
current = current.next
return dnaLL
I am trying to write a code to remove duplicates from a sorted linked list "head". My code below always returns the last duplicate if the list ends with a duplicate. for e.g. [1,2,2,3,3] will return [1,2,3,3]. I can't figure out why. Does anyone have an idea?
class Solution(object):
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head:
return head
l1=newhead=ListNode(head.val)
head=head.next
while head:
if head.val!=l1.val:
l1.next=head
l1=l1.next
head=head.next
return newhead
You should keep track of the leading node of each new value and keep fetching the next node until you get a node with a different value, at which point you assign that node as the next node for the leading node:
class Solution(object):
def deleteDuplicates(self, head):
node = head
while node:
lead = node
while node.next and node.next.val == lead.val:
node = node.next
node = lead.next = node.next
return head
Problem Solution
Create a class Node with instance variables data and next.
Create a class LinkedList with instance variables head and last_node.
The variable head points to the first element in the linked list while last_node points to the last.
Define methods append, get_prev_node, remove and display.
The method append takes a data item as argument and appends a node with that data item to the list.
The method get_prev_node takes a reference node as argument and returns the previous node. It returns None when the reference node is the first node.
The method remove takes a node as argument and removes it from the list.
The method display traverses the list from the first node and prints the data of each node.
Define a function remove_duplicates which takes a linked list as argument and removes duplicates from it.
The function remove_duplicates uses two nested loops to remove duplicate nodes.
Create an instance of LinkedList, remove duplicate nodes and display the list.
Program/Source Code
Here is the source code of a Python program to remove duplicates from a linked list.
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
self.last_node = None
def append(self, data):
if self.last_node is None:
self.head = Node(data)
self.last_node = self.head
else:
self.last_node.next = Node(data)
self.last_node = self.last_node.next
def get_prev_node(self, ref_node):
current = self.head
while (current and current.next != ref_node):
current = current.next
return current
def remove(self, node):
prev_node = self.get_prev_node(node)
if prev_node is None:
self.head = self.head.next
else:
prev_node.next = node.next
def display(self):
current = self.head
while current:
print(current.data, end = ' ')
current = current.next
def remove_duplicates(llist):
current1 = llist.head
while current1:
data = current1.data
current2 = current1.next
while current2:
if current2.data == data:
llist.remove(current2)
current2 = current2.next
current1 = current1.next
a_llist = LinkedList()
data_list = input('Please enter the elements in the linked list: ').split()
for data in data_list:
a_llist.append(int(data))
remove_duplicates(a_llist)
print('The list with duplicates removed: ')
a_llist.display()
Program Explanation
An instance of LinkedList is created.
The user is prompted to enter the data items for the list.
The function remove_duplicates is called to remove duplicates from the list.
The linked list is displayed.