I have a Linked Lists assignment for school although I am just getting the hang of class constructors. I am trying to simply get the basics of the linked list data structure down, and I understand the basic concept. I have watched lots of Youtube tutorials and the like, but where I am failing to understand is how to print out the cargo or data in my nodes using a loop.
I have written something along these lines:
class Node:
def __init__(self, value, pointer):
self.value = value
self.pointer = pointer
node4 = Node(31, None)
node3 = Node(37, None)
node2 = Node(62, None)
node1 = Node(23, None)
Now...I understand that each node declaration is a call to the class constructor of Node and that the list is linked because each node contains a pointer to the next node, but I simply don't understand how to print them out using a loop. I've seen examples using global variables for the "head" and I've seen subclasses created to accomplish the task. I'm old and dumb. I was wondering if someone could take it slow and explain it to me like I'm 5. If anyone out there has the compassion and willingness to hold my hand through the explanation, I would be greatly obliged. Thank you in advance, kind sirs.
First of all, your nodes should be created something like this :
node4 = Node(31, node3)
node3 = Node(37, node2)
node2 = Node(62, node1)
node1 = Node(23, None)
Now, i am sure you can see that the last node in the list would point to None. So, therefore, you can loop through the list until you encounter None. Something like this should work :
printhead = node4
while True:
print(printhead.value)
if printhead.pointer is None:
break;
else :
printhead = printhead.pointer
This is a very basic linked list implementation for educational purposes only.
from __future__ import print_function
"""The above is needed for Python 2.x unless you change
`print(node.value)` into `print node.value`"""
class Node(object):
"""This class represents list item (node)"""
def __init__(self, value, next_node):
"""Store item value and pointer to the next node"""
self.value = value
self.next_node = next_node
class LinkedList(object):
"""This class represents linked list"""
def __init__(self, *values):
"""Create nodes and store reference to the first node"""
node = None
# Create nodes in reversed order as each node needs to store reference to next node
for value in reversed(values):
node = Node(value, node)
self.first_node = node
# Initialize current_node for iterator
self.current_node = self.first_node
def __iter__(self):
"""Tell Python that this class is iterable"""
return self
def __next__(self):
"""Return next node from the linked list"""
# If previous call marked iteration as done, let's really finish it
if isinstance(self.current_node, StopIteration):
stop_iteration = self.current_node
# Reset current_node back to reference first_node
self.current_node = self.first_node
# Raise StopIteration to exit for loop
raise stop_iteration
# Take the current_node into local variable
node = self.current_node
# If next_node is None, then the current_node is the last one, let's mark this with StopIteration instance
if node.next_node is None:
self.current_node = StopIteration()
else:
# Put next_node reference into current_node
self.current_node = self.current_node.next_node
return node
linked_list = LinkedList(31, 37, 62, 23)
for node in linked_list:
print(node.value)
This doesn't handle many cases properly (including break statement in the loop body) but the goal is to show minimum requirements for linked list implementation in Python.
Related
I tried program to delete node from linked list recursively. My program is given below
class node:
def __init__(self, data=None):
self.data = data
self.next = None
class linkedList:
def __init__(self):
self.head=None
def printList(self):
cur = self.head
while(cur != None):
print(cur.data,end="->")
cur=cur.next
print("null")
def push(self,dat):
newNode = node(dat)
temp = self.head
self.head = newNode
newNode.next = temp
#staticmethod
def dnr(head, key):
if head is not None:
if head.data == key:
head=head.next
return head
if head is not None:
head.next = linkedList.dnr(head.next, key)
return head
return head
if __name__ == '__main__':
ll=linkedList()
ll.push(3)
ll.push(6)
ll.push(9)
ll.push(12)
ll.push(15)
ll.printList()
print("*******")
# ll.head = linkedList.dnr(ll.head,2)
linkedList.dnr(ll.head,9)
ll.printList()
The problem with this is that this does not work for first element.To make it work for first element I have to call the function like this
ll.head = linkedList.dnr(ll.head,2)
second thing is that I wanted my function to call this way
ll.dnr(2)
please tell me how to create a recursive function to delete node in linked list in python
I rewrote your code:
class node:
def __init__(self, data=None):
self.data = data
self.next = None
class linkedList:
def __init__(self):
self.__head=None
def printList(self):
cur = self.__head
while(cur != None):
print(cur.data,end="->")
cur=cur.next
print("null")
def push(self,dat):
newNode = node(dat)
temp = self.__head
self.__head = newNode
newNode.next = temp
#staticmethod
def __dnr(head, key):
if head is None:
return head
if head.data == key:
head = head.next
return head
head.next = linkedList.__dnr(head.next, key)
return head
#staticmethod
def dnr(listObj, key):
if listObj is None or listObj.__head is None:
return listObj
if listObj.__head.data == key:
listObj.__head = listObj.__head
listObj.__head = linkedList.__dnr(listObj.__head, key)
def deleteKey(self, key):
linkedList.dnr(self, key)
if __name__ == '__main__':
ll=linkedList()
ll.push(3)
ll.push(6)
ll.push(9)
ll.push(12)
ll.push(15)
ll.printList()
print("*******")
linkedList.dnr(ll, 9)
ll.deleteKey(12)
ll.printList()
I made head variable inside linkedList class private, it's not smart to give access outer world to class core components. And class core components should never leak to the outer world because if it's that not used properly that can cause errors. So I rewrote your dnr function and now it's more clear and it doesn't return head object which is core component of linkedList class. Now dnr function just check if passed listObj is valid and check if head is that node that should be deleted. After that it calls private static __dnr function to delete node with given key. Function deleteKey can be called like this ll.deleteKey(12), that is what you wanted.
Giving core component accessible through outer world is like giving bank customer access to a bank vault. Not everybody will try to steal money from it, but there will be someone who will try.
If you don't understand private variables follow this link.
I wanted my function to call this way ll.dnr(2)
Then you need to define an instance method. Your static function can serve a purpose, but as you noted, you really need to assign its return value back to your list's head attribute to be sure it also works when the original head node is removed. With your static method you cannot avoid this overhead, since that method has no knowledge about your linkedList instance.
You can achieve what you want simply by adding an instance method, that will rely on the existing static method and will deal with this assignment back to the instance's head attribute.
Add this to your linkedList class:
def remove(self, key):
self.head = linkedList.dnr(self.head, key)
Now in your main program you can do:
ll.remove(15)
Side note: you don't need the second if head is not None: check in your static method, as this condition will always be true when the execution reaches that point in your code. Just do the assignment to head.next unconditionally.
Addendum
If you want dnr itself to become an instance method (without addition of a remove method), then you need to temporarily cut off the head node from the list (even if you want to keep it), recur, and then conditionally add that cut-off node again (if it's key is not the one to delete).
It would look like this:
def dnr(self, key):
head = self.head
if head:
self.head = head.next # Skip
if head.data != key: # Need to restore it
self.dnr(key) # But first look further...
head.next = self.head # Prefix the removed node
self.head = head # ...and make it the head again
You would call like:
ll.dnr(15)
I'm writing a linked list in Python and I've come across an issue which is really troublesome and terrible for debugging and I feel like I'm missing something about Python. I'm supposed to create a singly linked list with some basic functionalities. One of them is the take() function, which is meant to create a new list of n first elements of the original list.
However, creating a new instance of the LinkedList class seems to change the .self parameter and the variable node is modified, as the attribute .next is turned to None. In result, when creating a list and then trying to make a new one out of the n elements of it, the program runs indefinitely, but no matter which part I look at, I cannot find the loop or the reason behind it.
class LinkedList:
def __init__(self, head=None):
self.head = head
def is_empty(self):
if self.head == None:
return True
else:
return False
def add_last(self, node):
if self.is_empty():
self.head = node
return
nextEl = self.head
while True:
if nextEl.next is None:
nextEl.next = node
return
nextEl = nextEl.next
def take(self, n):
node = self.head
newHead = self.head
newHead.next = None
newList = LinkedList(newHead)
count = 0
while count < n:
newList.add_last(node.next)
node = node.next
count += 1
return newList
class Node:
def __init__(self, data, next=None):
self.data = data
self.next = next
Thank you for all your help.
In the take() function the line
newHead.next = None
modifies a node of the linked list, breaking this list. You can fix this as follows:
def take(self, n):
node = self.head
newHead = Node(self.head.data)
newList = LinkedList(newHead)
count = 0
while count < n:
newList.add_last(node.next)
node = node.next
count += 1
return newList
This, however, still will not work correctly since there is a problem with the add_last() function too. This function, I think, is supposed to add a node as the last element of a linked list, but since you do not modify the next attribute of the node, you actually append a whole linked list starting with that node. This can be fixed in the following way:
def add_last(self, node):
if self.is_empty():
self.head = node
return
nextEl = self.head
while True:
if nextEl.next is None:
nextEl.next = Node(node.data)
return
nextEl = nextEl.next
There are more issues. For example, take(sefl, n) will actually create a list of n+1 elements and will throw an exception if it is applied to a linked list that does not have that many elements.
Note: I prefer to not use any external module since it is for interview prep purpose.
I know that there is no a built-in linked-list DS in python. However, we can implement the linked-list through a class Node. In the following code, I did a method (intersect_ll) to find an intersection between two linkedlists where the definition of intersections: node(s) are in the same order and value in the both linkedlists:
class Node:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
class SingleLinkedList:
def __init__(self):
self.head = None
def add_node(self, data):
newNode = Node(data)
if self.head:
current = self.head
while current.next:
current = current.next
current.next = newNode
else:
self.head = newNode
def print_ll(self):
current = self.head
ll_data = []
while current:
ll_data += [current.data]
current = current.next
return ll_data
def intesect_ll (self, first_ll, second_ll):
current_first = first_ll.head
current_second = second_ll.head
if current_first is None or current_second is None:
return False
list_intersect = []
while current_first and current_second:
if current_first.data == current_second.data:
list_intersect += [current_first.data]
current_first = current_first.next
current_second = current_second.next
for item in list_intersect:
self.add_node(item)
return self.print_ll()
My Question is: :
I am pretty new to python so I am struggling to understand why comparing instead by memory reference is not working. In other word, why python did not give these two nodes with the same value and order in both linkedlists, the same memory location ?!. Is that because I am implementing my own data-structure and hence,I assume that python would take care of the rest which is not the reality?
if current_first is current_second
compiler result:
it gives two different memory references for the both nodes of the same value and order in both linkedlists. Hence, this does not work and need to make it (.data) comparing by value then.
I found out that what I expect from python to do in terms of memory management is not that what really happens. I need to allocate the same object and then reference it in both linked lists in order to comparing by reference becomes a valid solution.
assign ObjectA : locationA in memory
linkedlist1: node.next --> LocationA ---> n nodes
linkedlist2: node.next --> LocationA ----> k nodes
Otherwise, they are completely two different linkedlists and the interpreter would assign each one of the nodes into different memory location:
linkedlist1: node.next ---> locationX -- n nodes
linkedlist2: node.next ---> locationY --- k nodes
Hope that helps anyone would have the same concern
I am brushing up on some data structures and algorithms with Python, so I am implementing an Unordered Linked list. Within the same file I first wrote a Node class followed by a List class. What I don't get is how the "current" variable in my search_item() method seems to be a node object or at least able to access the Node class methods and attributes. I noticed that if I comment out my add_node() method then "current" no longer has access to Node's methods. Now I am not explicitly using neither inheritance nor composition, so I am having a hard time seeing how current just gets to call get_next() the way the code is written below. I would think I'd have to declare current as: current = Node(self.head) but just current = self.head seems to work?
Your help would be greatly appreciated.
class Node:
def __init__(self, data):
self.data = data
self.next = None
def get_data(self):
return self.data
def set_data(self, d):
self.data = d
def get_next(self):
return self .next
def set_next(self, n):
self.next = n
class UnorderedList:
def __init__(self):
self.head = None
def add_node(self, item):
tmp = Node(item)
tmp.set_next(self.head)
self.head = tmp
def search_item(self, item):
current = self.head
# current = Node(self.head)
found = False
while current != None and not found:
if current.get_data() == item:
found = True
else:
current = current.get_next()
return found
Well if you comment out add_node then you do not add nodes to your linked list any longer therefore search_item will always see the initial value of self.head which is None.
Calling current.get_next() just works because via add_node you always ensure that self.head points either to None or to an instance of Node as tmp is created by tmp = Node(item) and then assigned to self.head = tmp. Therefore when setting current = self.head it will already refer to an instance of Node (or None) so you do not need to call current = Node(self.head).
I just recently came across the concept of duck typing and this old post of mine came to mind. It seems that this is what's at play and just didn't understand it at the time. 'current' is set to None by default, by when invoking any of the methods defined in the Node class, it is automatically defined as Node object.
I have my tree data structure as below:
class Node(object):
def __init__(self, data):
self.data = data
self.children = []
def add_child(self, obj):
self.children.append(obj)
Then I created a method to accomplish it.
def replace(node, newNode):
if node.data == 1:
node = newNode
return
else:
for i in xrange(0, len(node.children)):
replace(node.children[i], newNode)
This method is called just like that:
replace(mytree,newNode)
Since it is recursive call, I think the object get destroyed and the assignment does not happen.
I tried it manually as:
mytree.children[0].children[0] = newNode
then the tree is correctly updated. How can I achieve it using my method above?
The assignment node = newNode doesn't do what you want. It doesn't replace the object you know as node with newNode everywhere. It just rebinds the local variable name node to point to the same object as the other local name newNode. Other references to the first node (such as in its parent's children list) will be unchanged.
To actually do what you want requires more subtlety. The best approach is often often not to replace the node at all, but rather to replace its contents. That is, set node.data and node.children to be equal to newNode.data and newNode.children and leave node in place. This only fails to work properly if there are other references to node or newNode and you want them to work properly after the replacement.
The alternative is to do the replacement in the parent of the node you're looking for. This won't work at the top of your tree, so you'll need special logic to handle that situation.
def replace(node, newNode):
if node.value == 1:
raise ValueError("can't replace the current node this way")
for index, child in enumerate(node.children):
if child.data == 1:
node.children[index] = newNode
return True
if replace(child, newNode):
return True
return False
I've also added some extra logic to stop the recursive processing of the tree when the appropriate node has been found. The function will return True if a replacement has been made, or False if the right data value was not found.