Basically, I'm implementing a LinkedList class and then implementing various methods to use it. Below is the code for the LinkedList class(and its dependent Node class)
# A simple linked list implementation
class Node:
# attributes:
# data (can be anything)
# next (another Node)
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
# attributes:
# head (a Node)
# ****************
# methods:
# insert
# find
# delete
def __init__(self):
self.head = None
def __str__(self):
output = []
current_node = self.head
while current_node:
output.append(str(current_node.data))
current_node = current_node.next
return(", ".join(output))
# Creates a Node with the given data and inserts into the front of the list.
def insert(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
# Finds the first node with the given data. Returns None if there is no such node.
def find(self, data):
current_node = self.head
while(current_node):
if (current_node.data == data):
return current_node
current_node = current_node.next
return None # We reached the end of the list without finding anything.
# Deletes given node. Can be used in conjunction with find.
def delete(self, deleted_node):
if deleted_node == self.head:
self.head = self.head.next
return
current_node = self.head
while(current_node.next != deleted_node):
current_node = current_node.next
current_node.next = deleted_node.next
Then, I'm trying to implement a rotate(my_list, N) function, which will, well, rotate my_list by N. The following is my code:
import linkedlists as ll
from ErrorHandler import sanitize
import random, math, time, copy
def length(my_list):
sanitize(my_list, ll.LinkedList)
if my_list.head == None: return 0
count = 1 #First item! Ah, ah, ah
current_node = my_list.head
while current_node.next != None:
current_node = current_node.next
count += 1 #One more item! Ah, ah, ah
return count
def get_Nth(my_list, N):
sanitize(my_list, ll.LinkedList)
if my_list.head == None: return None
current_node = my_list.head
count = 0
while current_node.next != None:
if count == N:
return current_node
count +=1
current_node = current_node.next
return current_node
def rotate(my_list, N):
sanitize(my_list, ll.LinkedList)
if my_list.head == None: return None
N = N % length(my_list)
lent = length(my_list)
get_Nth(my_list, lent-1).next = my_list.head
my_list.head = get_Nth(my_list, lent-N)
get_Nth(my_list, lent-N-1).next = None
However, calling rotate() on a LinkedList containing the numbers from 0 to 9 in ascending order returns 8,9,0,1,2,3,4,5. Why? I'm pretty sure it has to do with the third- and second-to-last lines, because when assigning get_Nth(my_list, lent-1).next to my_list.head, it only points to my_list.head, instead of the Node object my_list.head points to at the time.
How can I fix this?
Your error is right here: get_Nth(my_list, lent-N-1).next = None
I'm assuming you called rotate(my_list, 2) so at this point, the list looks like this [8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, ...]. So when you call get_Nth(my_list, lent-N-1), lent-N-1 is 7, and well, the element at index 7 is actually 5.
You should just use lent-1.
Related
why can't print reversed this double linked list by python?
always print 6 or None
please can anyone help me fast to pass this task
///////////////////////////////////////////////////////////////////////////
class Node:
def __init__(self, data=None, next=None, prev=None):
self.data = data
self.next = next
self.previous = prev
sample methods==>
def set_data(self, newData):
self.data = newData
def get_data(self):
return self.data
def set_next(self, newNext):
self.next = newNext
def get_next(self):
return self.next
def hasNext(self):
return self.next is not None
def set_previous(self, newprev):
self.previous = newprev
def get_previous(self):
return self.previous
def hasPrevious(self):
return self.previous is not None
class double===>
class DoubleLinkedList:
def __init__(self):
self.head = None
self.tail = None
def addAtStart(self, item):
newNode = Node(item)
if self.head is None:
self.head = self.tail = newNode
else:
newNode.set_next(self.head)
newNode.set_previous(None)
self.head.set_previous(newNode)
self.head = newNode
def size(self):
current = self.head
count = 0
while current is not None:
count += 1
current = current.get_next()
return count
here is the wrong method ==>
try to fix it without more changes
def printReverse(self):
current = self.head
while current:
temp = current.next
current.next = current.previous
current.previous = temp
current = current.previous
temp = self.head
self.head = self.tail
self.tail = temp
print("Nodes of doubly linked list reversed: ")
while current is not None:
print(current.data),
current = current.get_next()
call methods==>
new = DoubleLinkedList()
new.addAtStart(1)
new.addAtStart(2)
new.addAtStart(3)
new.printReverse()
Your printReverse seems to do something else than what its name suggests. I would think that this function would just iterate the list nodes in reversed order and print the values, but it actually reverses the list, and doesn't print the result because of a bug.
The error in your code is that the final loop has a condition that is guaranteed to be false. current is always None when it reaches that loop, so nothing gets printed there. This is easily fixed by initialising current just before the loop with:
current = self.head
That fixes your issue, but it is not nice to have a function that both reverses the list, and prints it. It is better practice to separate these two tasks. The method that reverses the list could be named reverse. Then add another method that allows iteration of the values in the list. This is done by defining __iter__. The caller can then easily print the list with that iterator.
Here is how that looks:
def reverse(self):
current = self.head
while current:
current.previous, current.next = current.next, current.previous
current = current.previous
self.head, self.tail = self.tail, self.head
def __iter__(self):
node = self.head
while node:
yield node.data
node = node.next
def __repr__(self):
return "->".join(map(repr, self))
The main program can then be:
lst = DoubleLinkedList()
lst.addAtStart(1)
lst.addAtStart(2)
lst.addAtStart(3)
print(lst)
lst.reverse()
print(lst)
im trying to implement the data structure skiplist in python but am a little stuck, specifically with how to implement insertion & print functions (to visualize it).
Any help, tips, explanations are super welcome, as i am a beginner. I understand the data structure, and wanna understand the implementation as well.
Idea was to print lvls like this
lvl 0 -inf, 1, 2, 3, inf
lvl 1 -inf, 2, inf
lvl 2 -inf, inf
Thanks !
import math
import random as rnd
# node class of skiplist, as given by instructor should have pointers to: pred, next, down
class node:
def __init__(self, key, value=None):
self.key = key
self.value = value
self.next = None
self.pred = None
self.down = None
class skipList:
def __init__(self):
self.head = node(-math.inf)
self.tail = node(math.inf)
self.head.next = self.tail
self.tail.pred = self.head
self.length = 0
self.height = 1
def createLevel(self): # creates new frame lvl with only -inf/inf as nodes
newHead = node(- math.inf)
newTail = node(math.inf)
newHead.next = newTail
newTail.pred = newHead
newHead.down = self.head
newTail.down = self.tail
self.head = newHead
self.tail = newTail
def newLevel(self, levels):
if levels >= self.height:
self.height += 1
self.createLevel()
def coinFlip(self): # see how many lvls item to be inserted in
x = rnd.randint(0, 1)
return x
def search(self, key): # search returns stack of nodes traversed to reach k
q = []
current_node = self.head
while current_node.down != None:
current_node = current_node.down
while current_node.next.key <= key:
current_node = current_node.next
q.append(current_node.key)
return q
def put(self, key, value):
q = self.search(key)
current_node = q.pop() # if k exists, insert new value in k
if current_node.key == key:
current_node.value = value
return
else: # else create k after current_node
while self.coinFlip() == 1: # check for how many levels
if q == []: # key is not in the skiplist, or skiplist empty
# stuck here. idea: createLevel(), create new_node in levels
# (unsure how to achieve this for all lvls at once/individually?
# adjust pointers
def printSkip(self): # or is it best to use the __str__ method, if so how?
xs = []
current_node = self.head
for level in range(self.height):
print("level", level)
while current_node.next != None:
xs.append(current_node.key)
current_node = current_node.next
print(xs)
so far I can only add to level 0, but when i want to add a new level with the createLevel() then the element doesnt get "put" in the skiplist, let alone adding an element on several levels..
On the print function, I've tried with 2 for loops, as well as a for + while loop (one to determine level and then append all keys before carrying on to next level) but ive only achieved to get level 0 printed and the level heights...
import math
import random as rnd
#node class of skiplist, as given by instructor should have pointers to: pred, next, down
class node:
def __init__(self, key, value = None):
self.key = key
self.value = value
self.next = None
self.pred = None
self.down = None
class skipList:
def __init__(self):
self.head = node(-math.inf)
self.tail = node(math.inf)
self.head.next = self.tail
self.tail.pred = self.head
self.length = 0
self.height = 1
def createLevel(self): #creates new frame lvl with only -inf/inf as nodes
newHead = node(- math.inf)
newTail = node(math.inf)
newHead.next = newTail
newTail.pred = newHead
newHead.down = self.head
newTail.down = self.tail
self.head = newHead
self.tail = newTail
def newLevel(self, levels):
if levels >= self.height :
self.height += 1
self.createLevel()
def coinFlip(self): #see how many lvls item to be inserted in
x = rnd.randint(0, 1)
return x
def search(self, key): # search returns stack of nodes traversed to reach k
q = []
current_node = self.head
while current_node.down != None :
current_node = current_node.down
while current_node.next.key
I'm having a difficult time trying to create a function in a queue class to remove a certain node with the argument being the value of the node.
class LinkedQ:
def __init__(self):
self._first = None
self._last = None
def enqueue(self,x):
ny = Node(x)
if self._first == None:
self._first = ny
self._last = ny
else:
self._last.next = ny
self._last = ny
def remove(self,x):
current_node = self._first
while x != current_node.data: #Node(x):
last_node = current_node
current_node = current_node.next
if current_node == Node(x):
last_node.next = current_node.next
return
def display(self):
if self._first == None:
return None
else:
elements = []
current_node = self._first
elements.append(current_node.data)
while current_node.next != None:
current_node = current_node.next
elements.append(current_node.data)
print(elements)
class Node:
def __init__(self, x, next = None):
self.data = x
self.next = next
p = LinkedQ()
p.enqueue(1)
p.enqueue(2)
p.enqueue(3)
p.enqueue(4)
p.enqueue(5)
p.display()
p.remove(3)
p.display()
So it's the function def remove(self,x) that I can't seem to get working. As it is right now I don't get an error message, but the output, using the def display(self):, is still the same:
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
meaning that the selected node hasn't been removed. Could somebody please tell me what I'm doing wrong? And how can I try to solve it instead? As you can see, I'm trying to solve it by changing the pointer of the previous node to point at the node that is located after our current node, making it disappear when nothing is pointing at it. That's how we are required to solve it.
PS. There are other functions in the code, such as enqueue() and isEmpty() but those aren't relevant in this case, they work properly as of now.
Others have already shown that the culprit was the line if current_node == Node(x):, which should be if current_node.data == x:, unless you want to define an __eq__ member function in Node
But IMHO it is not the only problem: a LinkedQ as pointers to the head and the tail of the list. If you remove the first or last element of the queue, you have to reset the corresponding pointer (or both is the list becomes empty).
Your while loop breaks before it is able to remove the right value. If you put a print inside your while loop, to print the value of current_node.data, you'll see you only go into the loop for Node(1) and Node(2). After Node(2) the while loop condition breaks.
You should probably do something more like this:
while True:
last_node = current_node
current_node = current_node.next
if current_node.data == x:
last_node.next = current_node.next
return
You have a bug in your remove method :
def remove(self,x):
current_node = self._first
while current_node and x != current_node.data:
last_node = current_node
current_node = current_node.next
if current_node.data == x: #<==== Here
last_node.next = current_node.next
return
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
I'm reading Cracking the Coding Interview and doing practice problems and I'm stuck on this one:
"Implement an algorithm to delete a node in the middle (i.e., any node but the first and the last node, not necessarily the exact middle) or a singly linked list, given only access to that node.
EXAMPLE
Input: the node from the linked list a->b->c->d->e->f
Result: nothing is returned, but the new linked list looks like a->b->d->e->f"
Here's my code :
class Node:
def __init__(self, data = None, nextnode = None):
self.data = data
self.nextnode = nextnode
def __str__(self):
return str(self.data)
class LinkedList():
def __init__(self, head = None):
self.head = head
def insert(self, data):
new_node = Node(data)
new_node.nextnode = self.head
self.head = new_node
def remove(self, data):
current = self.head
absent = True
if current == None: print('List is empty')
if current.data == data:
self.head = current.nextnode
absent = False
while current.nextnode:
if current.nextnode.data == data:
absent = False
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
else: current.nextnode = None
else: current = current.nextnode
if absent: print('Element not in list')
def size(self):
current = self.head
size = 0
while current:
current = current.nextnode
size += 1
return size
def find(self, data):
current = self.head
if current == None: print('List is empty')
search = True
while current and search:
if current.data == data:
print(current)
search = False
current = current.nextnode
if search: print('Not found')
def print_list(self):
current = self.head
while current:
print(current, end = ' ')
current = current.nextnode
print('')
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node1.nextnode = node2
node2.nextnode = node3
node3.nextnode = node4
list1 = LinkedList(node1)
list1.insert(2 ****EDITED node2 to 2 here****)
print_list(list1)
def delmid(ll, n):
current = ll.head
if current == n:
print('Can\'t delete first node')
return
while current.nextnode:
if current.nextnode == n:
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
return
else:
print('Can\'t delete last node')
return
delmid(list1, node2)
print_list(list1)
I can't figure out why it doesn't seem to think that ll.head and node2 are the same ... It does work if I get rid of the line list1.insert(node2) ...
I don't understand ...
EDIT: after reading the first sentence of the solution in the book, apparently i did it wrong anyways .... "given only access to that node" means you don't know the head of the list ... back to the drawing board ...
Because your insert method is wrong:
def insert(self, data):
new_node = Node(data)
new_node.nextnode = self.head
self.head = new_node
Your method does not insert node2 itself as a node: it creates a new node with node2 as payload (data). That is something different.
You can define a method:
def insert_node(self, node):
node.nextnode = self.head
self.head = new_node
Nevertheless this will create a loop since now node1 will be pointing to node2 and node2tonode1`. So the resulting linked list will be a rounded list with two elements, like:
node1 --> node2
^---------/
EDIT: since you solved that one. There is also a problem with your delmid method.
The main problem is that in your while loop you need to walk through the linked list, and you do not do that: current always remains the same, so:
def delmid(ll, n):
current = ll.head
if current == n:
print('Can\'t delete first node')
return
while current.nextnode:
if current.nextnode == n:
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
return
else:
print('Can\'t delete last node')
return
current = current.nextnode
Should fix that.
Insert operation
You misunderstood your own insert-implementation.
list1.insert(node2) inserts a new node with node2 as content:
def insert(self, data):
new_node = Node(data) # <== wrap node2 into another node instance
new_node.nextnode = self.head
self.head = new_node
Comparison of Nodes
The ==-operator internally works by calling the method __eq__(self, other). In your case you didn't provide and implementation for this method, so the default is used to compare by all variables, which includes nextnode. Thus two nodes can only be equal, if they are precisely the same. To get this corrected, use a custom comparison method in Node:
def __eq__(self, other):
return type(other) is Node && other.data == self.data
This __eq__-method would work by first checking that other definitely is of type Node and afterwards compare by the data stored in each instance.
Delmid
Going a bit further than the actual question:
while current.nextnode:
if current.nextnode == n:
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
return
else:
print('Can\'t delete last node')
return
This loop will run infinitely, unless the list has at most a size of 1. To fix this step through the list by current = current.nextnode.
Improving Delmid
The actual purpose of this task was to get you used to another way of manipulating linked lists: swapping.
Instead of searching the entire list for the predecessor of n, you could just check that n is neither the first nor the last node, swap out the value with the value of it's consecutive node and delete the consecutive node:
def delmid(ll, n):
if ll.head == n:
print('Can\'t delete first node')
return
if n.nextnode is None:
print('Can\'t delete last node')
return
# swap values
tmp = n.data
n.data = n.nextnode.data
n.nextnode.data = tmp
# remove node
n.nextnode = n.nextnode.nextnode