I'm a Noob, struggling to understand and implement a singly linked list, that adds items at the tail. I believe the only code that is not working is the add function, which I can't figure out the logic for. I believe I want to set the first node to be the head, and then insert each other element at the tail, changing the pointer for head to point to the 2nd item when adding it, then the pointer for the 2nd item to point to the third etc., but can't figure out how to go about coding that (to deal with an unknown number of strings, here 3 for simplicity.
strings = ["one", "two", "three"]
class Node:
def __init__(self,data,nextNode=None):
# populate the Node, with data and pointer
self.data = data
self.nextNode = nextNode
def getData(self):
# method to get value of this node
return self.data
def setData(self,val):
# set value of node to val
self.data = val
def getNextNode(self):
# get the pointer to the next node
return self.nextNode
def setNextNode(self,val):
# set pointer to the next node
self.nextNode = val
class LinkedList:
def __init__(self, head = None, tail = None):
# initial properties of linked list, size 0
self.head = head
self.tail = tail
self.size = 0
def getSize(self):
# get size of linked list
return self.size
def addNode(self,data):
# Head should point to first node, which will have a value, and a Null pointer
if (self.size == 0):
newNode = Node(data, self.tail)
self.head.getNextNode() = newNode
else:
# All additional nodes should be inserted at tail, and with the pointers for the prior nodes changed to point to the new node
newNode = Node(data, self.tail)
self.tail = newNode
self.size += 1
return True
def printNode(self):
curr = self.head
while curr:
print(curr.data)#, curr.nextNode)
curr = curr.getNextNode()
mylist = LinkedList()
for i in strings:
mylist.addNode(i)
mylist.printNode()
# desired output: Head -> one --> two --> three/Tail
There were many little mistakes, please find them in code below. And let me know if you don't understand something.
One important change is a new node shouldn't have access to its next node. Its already the last node, so there can't be any node next to it. Also please pay close attention to else block of addNode function.
strings = ["one", "two", "three","four","five"]
class Node:
def __init__(self,data):
# populate the Node, with data and pointer
self.data = data
self.nextNode = None
def getData(self):
# method to get value of this node
return self.data
def setData(self,val):
# set value of node to val
self.data = val
def getNextNode(self):
# get the pointer to the next node
return self.nextNode
def setNextNode(self,val):
# set pointer to the next node
self.nextNode = val
class LinkedList:
def __init__(self, head = None, tail = None):
# initial properties of linked list, size 0
self.head = head
self.tail = tail
self.size = 0
def getSize(self):
# get size of linked list
return self.size
def addNode(self,data):
# Head should point to first node, which will have a value, and a Null pointer
if (self.size == 0):
self.head = Node(data)
self.tail = self.head
self.size = 1
else:
# All additional nodes should be inserted at tail, and with the pointers for the prior nodes changed to point to the new node
newNode = Node(data)
self.tail.nextNode = newNode
self.tail = newNode
self.size += 1
return True
def printNode(self):
curr = self.head
while curr:
print(curr.data)#, curr.nextNode)
curr = curr.getNextNode()
mylist = LinkedList()
for i in strings:
mylist.addNode(i)
mylist.printNode()
Related
I learned about linked-lists today. I learned how to insert and remove nodes from them. In the following code, it teaches me how to insert nodes with three distinct functions: at beginning (the head node), in between and at the end. However, they teach me how to remove the node in and single function. I don't find the code in the remove function to be very clear. Can anyone help make an easier to understand code under the remove function? Is there a way to make it into three functions just like the inserting ones? I'm open to any suggestion or explanation. Thanks in advance.
Here's my code:
class Node:
def __init__(self, data=None):
self.data = data
self.nextnode = None
class LinkedList:
def __init__(self):
self.headnode = None
def printlist(self):
node = self.headnode
while node is not None:
print (node.data)
node = node.nextnode
def atbegining(self,new_node):
new_node.nextnode = self.headnode
self.headnode = new_node
# Function to add newnode
def AtEnd(self, newnode):
if self.headnode is None:
self.headnode = newnode
return
node = self.headnode
while(node.nextnode):
node = node.nextnode
node.nextnode=newnode
# Function to add node
def Inbetween(self,preNode,newNode):
if preNode is None:
print("The mentioned node is absent")
return
newNode.nextnode = preNode.nextnode
preNode.nextnode = newNode
# Function to remove node
def RemoveNode(self, RemoveVal):
node = self.headnode
if (node is not None):
if (node.data == RemoveVal):
self.headnode = node.nextnode
node = None
return
while (node is not None):
if node.data == RemoveVal:
break
prevnode = node
node = node.nextnode
if (node == None):
return
prevnode.nextnode = node.nextnode
node = None
list1 = LinkedList()
list1.headnode = Node("Mon")
n2 = Node("Tue")
n3 = Node("Wed")
# Link first Node to second node
list1.headnode.nextnode = n2
# Link second Node to third node
n2.nextnode = n3
n4 = Node("Sun")
n5 = Node("Tur")
n6 = Node("Newdate")
list1.atbegining(n4)
list1.AtEnd(n5)
list1.Inbetween(list1.headnode,n6)
list1.RemoveNode("Newdate")
list1.printlist()
RemoveNode is complicated by the fact that there are two structurally distinct kinds of LinkedLists: one whose head is None, and one whose head is not None. You can fix this by making sure every LinkedList contains at least one node. This is typically referred to as a dummy node, and you can use this node to store metadata (such as the length of the list).
The Node class itself does not change.
class Node:
def __init__(self, data=None):
self.data = data
self.nextnode = None
The LinkedList, however, simplifies by creating a dummy node. This provides
the guarantee that every node that stores real data is point to by another node.
class LinkedList:
def __init__(self):
self.headnode = Node(0)
def insert(self, preNode, newNode):
newNode.nextnode = preNode.nextnode
preNode.nextnode = newNode
self.headnode.data += 1
def append(self, newNode):
curr = self.headnode
while curr.nextNode is not None:
curr = curr.nextNode
self.insert(curr, newNode)
def prepend(self, newNode):
self.insert(self.headnode, newNode)
def _find_before(self, val):
pre = self.headnode
while pre.nextnode is not None:
curr = pre.nextnode
if curr.data == val:
return pre
pre = curr
def remove(self, RemoveVal):
pre = self._find_before(RemoveVal)
if pre is None:
return
pre.nextnode = pre.nextnode.nextnode
self.headnode.data -= 1
This simplifies all three insertions. The general case can always apply, since there is always a node that comes before the node you insert. append and prepend are simple wrappers that find the appropriate node to pass to insert.
Likewise, remove simply finds the node before the given value, and if the search succeeds, handles updating the prior node's nextnode attribute.
insert and remove also update the size of the list stored in the dummy node.
A find method becomes a simple wrapper around _find_before; if you find a node before the value you are looking for, just return the node that follows it.
I think that an alternative design will make the code much clearer. Consider for example the following:
class Node:
def __init__(self, data=None):
self.data = data
self.nextnode = None
def printlist(self):
print(self.data)
if self.nextnode is not None:
self.nextnode.printlist()
def push(self, node):
node.nextnode = self
return node
def insertafter(self, node):
node.nextnode = self.nextnode
self.nextnode = node
return self
def append(self, node):
lastnode = self
while lastnode.nextnode is not None:
lastnode = lastnode.nextnode
lastnode.nextnode = node
return self
def remove(self, value):
prev = None
walk = self
while walk is not None:
if walk.data == value:
if prev is None:
return walk.nextnode
else:
prev.nextnode = walk.nextnode
return self
else:
prev = walk
walk = walk.nextnode
return self
list1 = Node("Mon")
n2 = Node("Tue")
n3 = Node("Wed")
# Link first Node to second node
list1 = list1.insertafter(n2)
# Link second Node to third node
n2 = n2.insertafter(n3)
n4 = Node("Sun")
n5 = Node("Tur")
n6 = Node("Newdate")
list1 = list1.push(n4)
list1 = list1.append(n5)
list1 = list1.insertafter(n6)
list1 = list1.remove("Newdate")
list1.printlist()
The main idea is that a Node is the linked list. As long as you have the head of the list kept in a variable, you can have access to the entire list, without the need for a separate data structure.
I need an insert to head operation for a linked list that I implemented. However, doing this operation by function call (like insertToHead) and writing the statements explicitly where I need them produces different results. I wonder which property of Python leads to that difference but I couldn't figure it out.
To be more specific, let's say that I have the following class for the linked list:
class Node:
value = None
nextNode = None
def __init__(self, value):
self.value = value
def insertToHead(self, value):
newHead = Node(value)
newHead.nextNode = self
return newHead
For a linked list with a single element (say, 2) I want to insert a node (say, 0) to the head to make linked list 0 -> 2.
I created the linked list the following way
head = Node(2)
Then I tried to insert 0 to head two ways:
Writing the statements explicitly where I need them
newHead = Node(0)
newHead.next = head
head = newHead
Now head is 0, not 0 -> 2.
Calling insertToHead
head = head.insertToHead(0)
head is 0 -> 2 after this statement.
Does anyone know why these two approaches result in differently?
You have a typo. newHead.next should be newHead.nextNode.
A simple implementation of Singly Linked Lists:
class Node:
def __init__(self, value = None, nextNode = None):
self.value = value
self.nextNode = nextNode
class LinkedList:
def __init__(self):
self.head = None # will point to the head of the list
self.tail = None # will point to the tail of the list
self.size = 0 # size of the linked list
def insert_to_head(self, data):
# when push front, the head of the linked list will be Node()
self.head = Node(data, self.head)
if self.tail == None: # if tail is None, means it is a single element
self.tail = self.head
self.size += 1 # increase size by one
def __str__(self):
ret_str = ""
node = self.head
while node != None:
ret_str += str(node.value) + " -> "
node = node.nextNode
return ret_str
myLinkedList = LinkedList()
myLinkedList.insert_to_head(3)
myLinkedList.insert_to_head(2)
print(myLinkedList)
I am currently taking an online computer science introductory course and have just learned the concept of a linked list. Though I understand the concept of linked lists, I still am unsure as how to deal with linked lists.
As such, I seek out help in solving the following problem, which will be of significant help for my understanding of linked lists:
Write a function (not in LinkedList class definition) that given a linked list, will change that linked list to filter out odd numbers. Immediately after the function returns, the linked list will only have even numbers.
I am unsure as to how to access the nodes in the list and check whether they are odd or even and remove or keep them accordingly.
I apologize if this seems like a trivial question, but I would appreciate any help that might help me learn.
The code for the linked list and node classes (as provided by the online course):
class Node:
def __init__(self, data=None, next_node=None):
self.data = data
self.next = next_node
def __str__(self):
return str(self.data)
class LinkedList:
def __init__(self):
self.length = 0
self.head = None
def print_list(self):
node = self.head
while node is not None:
print(node, end=' ')
node = node.next
print('')
def add_at_head(self, node):
node.next = self.head
self.head = node
self.length += 1
def remove_node_after(self, node):
if node.next is not None:
temp = node.next
node.next = node.next.next
temp.next = None
self.length -= 1
def remove_first_node(self):
if self.head is None:
return
temp = self.head
self.head = self.head.next
temp.next = None
self.length -= 1
def print_backward(self):
def print_nodes_backward(node):
if node.next is not None:
print_nodes_backward(node.next)
if node is not None:
print(node, end=' ')
if self.head is not None:
print_nodes_backward(self.head)
print('')
Let's say you have a bare-bones simple linked list that looks like this:
class LinkedList:
class ListNode:
def __init__(self, data):
self.data = data
self.next = None
def __init__(self):
self.head = None
def add(self, data):
if self.head is None:
self.head = LinkedList.ListNode(data)
else:
current_node = self.head
while current_node.next is not None:
current_node = current_node.next
current_node.next = LinkedList.ListNode(data)
def __str__(self):
ret = "["
current_node = self.head
while current_node is not None:
ret = ret + str(current_node.data)
if current_node.next is not None:
ret = ret + ", "
current_node = current_node.next
ret = ret + "]"
return ret
In other words, the LinkedList contains a single head, which is a ListNode. Every element in the Linked List is contained in a ListNode, and each ListNode points towards the next element in the list.
As you can see, for adding an element to the list, we either create a node at the head if the list is empty (i.e. self.head is None), or we traverse to the end of the list by continuously jumping to the .next element for each ListNode, starting from the head. We also use this paradigm for printing a string representation of our list.
So, to remove any node from the linked list, we can simply change the node that references it, so that the node we want to remove gets skipped. At which point it will disappear.
To remove all list nodes containing odd-numbered data, we might do something like this:
def remove_odds(self):
# special case: head node
# remove odd head elements by simply setting head to the next element after
while (self.head is not None) and (self.head.data % 2 == 1):
self.head = self.head.next
# regular case: the rest of the nodes
current_node = self.head
while (current_node is not None) and (current_node.next is not None):
# if the next node's data is odd, then
if current_node.next.data % 2 == 1:
# skip that node by pointing this node's .next to the next node's .next
current_node.next = current_node.next.next
# otherwise, move forwards in the list
else:
current_node = current_node.next
Proof of concept:
>>> lst = LinkedList()
>>> lst.add(2)
>>> lst.add(5)
>>> lst.add(6)
>>> lst.add(3)
>>> lst.add(7)
>>> lst.add(8)
>>> lst.add(10)
>>> lst.add(1)
>>> lst.add(4)
>>> print(lst)
[2, 5, 6, 3, 7, 8, 10, 1, 4]
>>> lst.remove_odds()
>>> print(lst)
[2, 6, 8, 10, 4]
Copied from comment: The idea is to iterate through the list head-to-tail while remembering the previous node; when you find a garbage node, apply remove_node_after to the remembered node, or move the head to the current node if we haven't had time to remember anything yet.
The code would be something like this (untested):
class LinkedList:
# ...
def delete_if(self, pred):
prev = None
curr = self.head
while curr:
if pred(curr.data):
if prev:
self.remove_node_after(prev)
else:
self.head = curr
prev = curr
curr = curr.next
llist.delete_if(lambda x: x % 2 == 1) # delete if odd
# Mahmoud AL-Mokdad
# this course on Udemy By SEfactoru right๐
# use my code ๐
def filter_even(ll):
first_node = ll.head
while (first_node is not None) and (first_node.data % 2 != 0):
ll.remove_first_node()
first_node = ll.head
node = first_node
while node is not None and node.next is not None:
if node.next.data % 2 != 0:
ll.remove_node_after(node)
else:
node = node.next
Below is my code in python. I'm basically trying to look through a linked list to see if a specific element is in that list. The code works if the item is in the list, but not if it doesn't. I believe the problem lies within the loop coming to the end of the list and the last node, but I'm not sure how to fix the error. Any help would be appreciated. (Edited to include the classes used)
class Node:
def __init__(self, data):
#raise error for wrong data input type
if not type(data) in [int, float, str]:
raise TypeError("data must be an integer, float, or string")
self.value = data
class LinkedListNode(Node):
def __init__(self, data):
Node.__init__(self, data) # Use inheritance to set self.value.
self.next = None # Reference to the next node.
self.prev = None # Reference to the previous node.
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def append(self, data):
# Create a new node to store the input data.
new_node = LinkedListNode(data)
if self.head is None:
# If the list is empty, assign the head and tail attributes to
# new_node, since it becomes the first and last node in the list.
self.head = new_node
self.tail = new_node
self.length += 1
else:
# If the list is not empty, place new_node after the tail.
self.tail.next = new_node # tail --> new_node
new_node.prev = self.tail # tail <-- new_node
# Now the last node in the list is new_node, so reassign the tail.
self.tail = new_node
self.length += 1
def find(self, data):
x = range(self.length)
current_position = self.head.value
current_node = self.head
for i in x:
if current_position == data:
return self.head
else:
current_node = current_node.next
current_position = current_node.value
if current_position != data:
raise ValueError("data point is not in the list")
return
I have made a Node and Deque class to represent a double linked list. I wrote a function to pop the last item of my list, but after executing the function it pops the first element instead.
My expected output:
my_list.push_front(1)
my_list.push_front(2)
my_list.push_front(3)
linked list is [3, 2, 1]
my_list.pop_back() --> [3,2]
My linked list function file:
class Node:
"""
Initialize empty node
"""
def __init__(self, data, prev = None, next = None):
self.data = data
self.next = next
self.prev = prev
class Deque:
"""
A double-ended queue
"""
def __init__(self):
"""
Initializes an empty Deque
"""
self.head = None
self.size = 1
def __len__(self):
"""
Computes the number of elements in the Deque
:return: The size of the Deque
"""
counter = 1
current = self.head
if self.head is None:
return 0
while current.next is not None:
counter += 1
current = current.next
return counter
def push_front(self, e): #needs work
"""
Inserts an element at the front of the Deque
:param e: An element to insert
"""
new_head = Node(data = e, next = self.head)
if self.head:
self.head.prev = new_head
self.head = new_head
def pop_back(self):
"""
Removes and returns the last element
:return: The (former) last element
"""
if self.head == None:
raise IndexError
curr = self.head
while curr.next:
curr = curr.next
save = self.head.data
self.head = self.head.next
self.size -= 1
return save
def listprint(self, node):
"""
Prints each element of the node front to back
:param node:
"""
while (node is not None):
print(node.data)
last = node
node = node.next
My main file:
def main():
my_list = Deque()
my_list.push_front(1)
my_list.push_front(2)
my_list.push_front(3)
my_list.pop_back()
my_list.listprint(my_list.head) #print elements in the list
In my pop_back() function, I was thinking of traversing until the end of the linked list, and then set self.head to self.head.next and decrease the size of the linked list by 1.
Here's what I think is the issue:
save = self.head.data
self.head = self.head.next
You want to remove the last one, but you're actually changing the reference for the head. If you want to change the reference of the last one, you should be doing:
while curr.next.next: # This allows you to stand on the previous of the last one
curr = curr.next
save = curr.next
curr.next = None
self.size -= 1
return save
The actual thing you're doing there it's a pop and not a dequeue