I am trying to implement Single Linked List on Python and the Code below works fine but I can not understand how:
class Node(object):
def __init__(self, data=None, ):
self.value = data
self.next = None
class LinkedList1(object):
def __init__(self, data=None):
self.head = Node(data)
self.tail = self.head
self.length = 1
def append(self, data):
self.tail.next = Node(data)
self.tail = self.tail.next
self.length += 1
return self
def show_list(self):
head_copy = self.head
while head_copy is not None:
print(head_copy.value)
head_copy = head_copy.next
When we test it:
linkin = LinkedList1(10)
linkin.append(20)
linkin.append(30)
linkin.append(40)
linkin.show_list()
output :
10
20
30
40
What I don't understand is append function. I know self.tail referencing self.head but how come sefl.tail.next adds the new Node(data) to the at the last next, in my logic without a loop it should add to first next.
Plus if we write the function this way:
def append(self, data):
self.head.next = Node(data)
self.tail = self.head.next
self.length += 1
return self
This doesn't work even if self.tail reference to self.head.
I know I am missing something here. Can you help me understand?
Thank you.
If you refer to the class Node, it has two objects: value and next Node.
In the Linked list implementation, it is implemented in such a way that the tail Node information is stored as well. In the append function, self.tail.next = Node(data) basically adds a new node after the tail node and self.tail = self.tail.next reassigns the Linked list's tail node to the newly created Node (which is now the last node of the list)
For example, let's take the following code:
linkin = LinkedList1(10)
linkin.append(20)
linkin.append(30)
linkin.append(40)
linkin.show_list()
A Linked list is created with self.head -> Node(10) and self.tail -> Node(10)
Appending 20 changes the list: self.head -> Node(10), self.tail.next -> Node(20) [which is same as self.head.next] 10 -> 20 where 10 is head and 20 is tail
Appending 30 changes the list: self.tail.next -> Node(30) [self.tail here is Node(20)] and Node(30) is now made as tail 10 -> 20 -> 30 where 10 is head and 30 is tail
Hope this helps.
self.tail is only set to self.head when there is a single node. tail is always changed to point to the LAST node, which is the same as the head node only before the second node is added.
Every time append is called, tail is changed to point to the node that was just added.
It doesn't make much sense to append to the first node, does it? That would get rid of the rest of the list.
Let's take it line by line:
def append(self, data):
self.tail.next = Node(data)
Before this is executed, self.tail.next is None, which indicates the list ends there. Now that we've set it to a new Node, that new node has a "next" value that is None.
self.tail = self.tail.next
Since self.tail needs to point to the LAST item in the list, we need to change it. So, the above line changes it to point to the NEW last item.
self.length += 1
return self
These just keep track of length and return. As long as it is done correctly, you won't need to run through the list just to know how many nodes are in it.
Related
The code works and outputs 1,5, and 6.
After print_list(), prints the first value ( 1 ), how does temp = temp.next result in temp.value being 5 on the next pass.
I am missing something but I've been at this for days. I just don't understand how temp.next is pointing at 5 or the next node.
I also understand that temp, head, and tail are pointers. Please help, I am trying to learn what every line of code is doing.
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__ (self, value):
new_node = Node(value)
self.head = new_node
self.tail = new_node
self.lenth = 1
def print_list(self):
temp = self.head
while temp is not None:
print(temp.value)
temp = temp.next
def append(self, value):
new_node = Node(value)
if self.head is None:
self.head = new_node
self.tail = new_node
else:
self.tail.next = new_node
self.tail = new_node
self.lenth =+ 1
return True
my_linked_list = LinkedList(1)
my_linked_list.append(5)
my_linked_list.append(6)
my_linked_list.print_list()
When thinking about a linked list data structure, you can conceptualize the structure as a list of boxes chained together, with the first box connected to the next, that one connected to the next, and so on, until you reach the last box and there's nothing it's chained to. Here's a rough visual demonstration:
[5] -> [7] -> [9] -> [3] -> None
This linking between boxes is denoted by having the first node of the linked list (a.k.a the head), have a reference to the next box in the list. In your code example this reference is stored in the next attribute. And this next node has a reference stored in it, which points to the next, next node. And this process continues on, creating the chain-like behavior I mentioned above.
What print_list is doing is starting at the head of the linked list, printing the head's data, and then using the reference the head has to the next box in the linked list to get that next box, print it's data, and then use this next boxes reference to get the next box in the list. This process continues on until the last box is reached, which has no further reference, so the code terminates (this is what the while temp is not None: condition checks for).
I commented each line below to connect what I said a bit more concretely to the actual code:
def print_list(self):
# Set temp to be equal to the first box in the list
temp = self.head
# temp will be set to none when we try to set it to be equal to
# the next box the last box in the list is pointing to. So we
# know we've reached the end of the list when temp is none,
# meaning we should break out of the loop and finish.
while temp is not None:
# Print the data in the current box, starting with head...
print(temp.value)
# And then get the next box in the list so we can print it's data.
temp = temp.next
I am new to classes in Python. I am trying to implement linked lists. Can someone please explain to me how self.head.next.value outputs the next value in the list? Even though next is assigned to none but somehow it is able to print the right answer. I saw a similar post here How does self.next = None get the next value of l1?
but the answer was not properly explained since I am not assigning anything to self.next.
class Element(object):
def __init__(self, value):
self.value = value
self.next = None
class LinkedList(object):
def __init__(self, head=None):
self.head = head
def append(self, new_element):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = new_element
else:
self.head = new_element
l = LinkedList(Element(1))
l.append(Element(2))
print (l.head.next.value)
The output shows :
2
[...] since I am not assigning anything to self.next.
Well, you initialize .next to None. Howeever, when you call append(), that changes the last element's .next:
current.next = new_element
I'm trying to create a function that takes in a head of a linked list and a value, create a node with that value, set node.next to head, and then update the the new node to be the head. I got it to work but I feel like I'm doing this very inefficiently by returning values, so I was wondering if there is a more elegant way to do this.
Here's the code I'm using:
#!/usr/bin/env python3
"""
This module is a linked list implementation.
"""
class Node:
"""
Node structure to be used in our linked list.
"""
def __init__(self, value):
self.value = value
self.next = None
def linked_insert(head, value):
"""
Insert new node to the tail of the linked list.
Time Complexity: O(n)
"""
current = head
while current.next is not None:
current = current.next
current.next = Node(value)
def linked_insert2(head, value):
"""
Insert new node to the head of the linked list, making sure to update head.
Time Complexity: O(1)
"""
to_insert = Node(value)
to_insert.next = head
head = to_insert
return head
def linked_extract(head):
"""
Extract the last element in the linked list
"""
current = head
while current.next.next is not None:
current = current.next
tail = current.next
current.next = None
return tail
def linked_display(head):
"""
Print all node values in the linked list
"""
current = head
while current is not None:
print(current.value)
current = current.next
# Test Program
head = Node(5)
# linked_insert(head, 1)
# linked_insert(head, 2)
# linked_insert(head, 3)
#
# print(linked_extract(head).value)
head = linked_insert2(head, 1)
head = linked_insert2(head, 2)
head = linked_insert2(head, 3)
linked_display(head)
Is there a way to do this without having to return the value of head and setting head = returned value in the test program?
The function in question is linked_insert2(). The whole program is meant to be a linked list implementation in python.
Implementation using linked list class:
#!/usr/bin/env python3
"""
This module is a linked list implementation.
"""
class Node:
"""
Node class to be used in our linked list.
"""
def __init__(self, value):
self.value = value
self.next = None
class Linkedlist:
"""
Linked list implementation that supports functions including inserting
at head, inserting at tail, extracting elements, and displaying all
elements in the ist
"""
def __init__(self, head):
self.head = Node(head)
def insert(self, value):
"""
Insert new node to the tail of the linked list.
Time Complexity: O(n)
"""
current = self.head
while current.next is not None:
current = current.next
current.next = Node(value)
def insert2(self, value):
"""
Insert new node to the head of the linked list, making sure to update head.
Time Complexity: O(1)
"""
to_insert = Node(value)
to_insert.next = self.head
self.head = to_insert
def extract(self):
"""
Extract the last element in the linked list
"""
current = self.head
while current.next.next is not None:
current = current.next
tail = current.next
current.next = None
return tail
def display(self):
"""
Print all node values in the linked list
"""
current = self.head
while current is not None:
print(current.value)
current = current.next
# Test Program
head = Linkedlist(5)
# linked_insert(head, 1)
# linked_insert(head, 2)
# linked_insert(head, 3)
head.insert2(1)
head.insert2(2)
head.insert2(3)
head.display()
AM Implementing a Queue in python. The code I have already done is below, but one thing am not able to figure out is how to delete the last item in the queue. My implementation is apparently correct. What am I missing in the code
class Queue:
class node:
def __init__(self):
self.data = None
self.next = None
def __init__(self):
self.cur_node = None
self.head = None
def isEmpty(self):
return self.head==None
def push(self,data):
new_node = self.node()
if self.head == None:
new_node.data=data
new_node.next=None
self.head = new_node
self.cur_node = None
else:
new_node.data = data
node=self.head
self.cur_node=node
new_node.next=self.cur_node
self.head=new_node
#set it to head and change current head to next
def list_print(self):
node = self.head
while node:
print (node.data)
node = node.next
def dequeue(self): # A Queue IMPLEMENTS ITS STRUCTURE AS FIFO ( First IN First OUT)
if self.head == None:
raise Exception("Queue is empty")
else:# Remove the last item which entered first
node=self.head
prevnode=node
nodetodel=node
while node:
if node.next==None:
nodetodel=node
print(node.data)
node=node.next
else:
#print(node.data)
node=node.next
prevnode=node
self.cur_node=prevnode
self.cur_node.next=None
print(node.data)
del(node)
lyst = ["Bill", "David", "Susan", "Jane", "Kent", "Brad"]
n=Queue()
for name in lyst:
n.push(name)
n.dequeue()
#n.list_print()
print("Done")
It looks to me as if you've implemented your Queue backwards. Shouldn't head keep track of the oldest value in the Queue? Then to dequeue, you just do something like self.head = self.head.next. Here's a quick implementation
class Queue:
class EmptyQueue(Exception):
def __str__(self):
return "Queue is empty, cannot dequeue."
class node:
def __init__(self, data, next):
self.data = data
self.next = next
def __init__(self, seq=None):
self.head = None #Oldest item in queue
self.tail = None #Youngest item in queue
if seq:
for item in seq:
self.enqueue(item)
def enqueue(self, item):
new_node = Queue.node(item, None)
if not self.tail: #queue empty
self.head = new_node
self.tail = new_node
else:
self.tail.next = new_node
self.tail = new_node
def dequeue(self):
if self.head:
data = self.head.data
self.head = self.head.next
return data
else:
raise Queue.EmptyQueue
def list_print(self):
curr = self.head
while curr:
print(curr.data)
curr = curr.next
What am I missing in the code
nodetodel is not used
#print(node.data)
node=node.next
prevnode=node
You should set prevnode before changing node, not after.
self.cur_node=prevnode
self.cur_node.next=None
cur_node is useless as member variable, you don't use it in any condition, local variable will do this work easily and you already have one (prevnode)
print(node.data)
del(node)
By the time of execution of these 2 lines you already have node==None and it's the cause of program crash. Probably you wanted to use nodetodel intead.
P.S. I'm just pointing out what you missed in your code - as you asked. I hope it will be helpful, even though I personally believe after fixes and making sure it can work somehow you'll think about #PatrickHaugh answer and start over from scratch.
You implementation of queue is quite inefficient, as it has to traverse through every element of linked list. The key to optimization in head/tail keeping is to avoid requirement for getting through the whole list to perform push/pop.
The if node.next==None part in dequeue is wrong in the context of the print statement. I think the following is more correct (I've also simplified):
def dequeue(self): # A Queue IMPLEMENTS ITS STRUCTURE AS FIFO ( First IN First OUT)
if self.head == None:
raise Exception("Queue is empty")
else:# Remove the last item which entered first
node=self.head
prev = None
while node:
if node.next:
prev = node = node.next
else:
self.cur_node = prev
if prev:
prev.next = None
return node.data
But in real usage you'd probably just use the built-in list (which can be used as a queue) or the queue.queue, the later is concurrent safe.
I've created a linked list in Python, and it is singly linked. This works perfectly fine, but I want to implement it so it's doubly linked, but I'm having trouble figuring out how to do it.
# node class
class node:
def __init__(self):
self.data = None # contains the data
self.next = None # contains the reference to the next node
# linked list class
class linked_list:
def __init__(self):
self.cur_node = None
def add_node(self, data):
new_node = node() # create a new node
new_node.data = data
new_node.next = self.cur_node # link the new node to the 'previous' node.
self.cur_node = new_node # set the current node to the new one.
def list_print(self):
node = self.cur_node # cant point to ll!
while node:
print(node.data)
node = node.next
I know I need to add self.previous to the node class, and I think I need to add something to the linked list constructor and add_node function, but I'm not sure where to start.
I don't actually need to use this functionality in a program, I'm just trying to learn about how linked lists are implemented at a lower level.
It's not so much a coding problem as a conceptual problem. You need to figure out how you want your code to behave. Implementing the desired behavior is not (in this case) at all difficult.
Say we want these behaviors:
# construction
dlist = DoublyLinkedList()
# access to head and tail nodes
dlist.head # should return the head node
dlist.tail # should return the tail node
dlist.head.prev is None # should be True
dlist.tail.next is None # should be True
# adding nodes at both ends
dlist.add_head()
dlist.add_tail()
# iteration in both directions
for node in dlist:
# do something to the node
for node in reversed(dlist):
# do something to the node
When you have written out the desired behavior like this, you'll also have got some test code ready.
Now let's start by modifying the Node class (you should use CamelCase for class names):
class Node:
def __init__(self, data=None, prev=None, next=None):
self.data = data
self.prev = prev
self.next = next
def __repr__(self):
return '<{}, {}>'.format(self.data, self.next)
We add prev since that's obviously needed. But we also improve on your original version by having data and next as parameters, so you can have these values set when a node is created. And __repr__ is always nice to have, for debugging if not for anything else.
Now for the list itself. The key is, (a) instead of one cur_node, you need two handles on the list, which I've been calling head and tail, and (b) when adding nodes, the very first node is a special case where we have to make changes to both head and tail.
class DoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def __repr__(self):
return '<DoublyLinkedList {}>'.format(self.head)
def add_head(self, data=None):
if self.head is None:
self.head = self.tail = Node(data) # the very fist node
else:
new_head = Node(data=data, next=self.head) # prev is None
self.head.prev = self.head = new_head
def add_tail(self, data=None):
if self.tail is None:
self.head = self.tail = Node(data) # the very first node
else:
new_tail = Node(data=data, prev=self.tail) # next is None
self.tail.next = self.tail = new_tail
# implements iteration from head to tail
def __iter__(self):
current = self.head
while current is not None:
yield current
current= current.next
# implements iteration from tail to head
def __reversed__(self):
current = self.tail
while current is not None:
yield current
current = current.prev
Let's test this
>>> dlist = DoublyLinkedList()
>>> print(dlist)
<DoublyLinkedList None>
>>> dlist.add_head(1)
>>> dlist.add_tail(2)
>>> dlist.add_tail(3)
>>> dlist.add_head(0)
>>> print(dlist) # __repr__ is such a nice thing to have
<DoublyLinkedList <0, <1, <2, <3, None>>>>>
>>> print(dlist.head)
<0, <1, <2, <3, None>>>>
>>> print(dlist.tail)
<3, None>
>>> print(dlist.head.prev is None, dlist.tail.next is None)
True, True
>>> print(dlist.tail.prev.next is dlist.tail)
True
>>> [node.data for node in dlist]
[0, 1, 2, 3]
>>> for node in reversed(dlist):
... print(node.data, node)
3 <3, None>
2 <2, <3, None>>
1 <1, <2, <3, None>>>
0 <0, <1, <2, <3, None>>>>
For a doubly linked list, you should have, each node should have a reference to the previous node. This means that you will need to modify your add and remove methods to also assign this reference.