Deleting a node from Linked List having "sentinels" - python

I am trying to write a Linked List having sentinels as per the CLRS book. My remove function for some reason removes a chunk of LL upto the node to be deleted. Attached is my code. Any suggestion will be deeply appreciated.
class Node():
def __init__(self,v):
self.value = v
self.next = None
self.prev = None
def getValue(self):
return self.value
def changeValue(self,v):
self.value = v
def getNext(self):
return self.next
def getPrev(self):
return self.prev
def setNext(self,newNext):
self.next = newNext
def setPrev(self,newPrev):
self.prev = newPrev
class List(Node):
def __init__(self):
self.nil = Node(None)
def addNode(self,v):
a = Node(v)
a.setNext(self.nil.next)
a.setPrev(self.nil)
self.nil.next = a
def length(self):
count = 0
a = self.nil
while(a.next != None):
count += 1
a = a.getNext()
return count
def search(self,v):
a = self.nil
while(a.next != None):
if (a.value == v):
return True
a = a.getNext()
return False
def remove(self,v):
a = self.nil.next
breakloop = 0
while((a.next != None) and (breakloop == 0)):
if (a.value == v):
a.prev.next = a.next
a.next.prev = a.prev
breakloop = 1
a = a.getNext()
def printList(self):
a = self.nil.next
while(a.next != None):
print(a.value)
a =a.getNext()
print(a.value)
a = List()
a.addNode(4)
a.addNode(7)
a.addNode(2)
a.addNode(6)
a.addNode(5)
a.addNode(8)
a.addNode(1)
a.addNode(14)
a.addNode(13)
a.addNode(17)
a.addNode(18)
a.printList()
a.remove(13)
a.printList()
The output will be
18 17 13 14 1 8 5 6 2 7 4
14 1 8 5 6 2 7 4

#tcaswell has correctly diagnosed the problem with the code: you're not setting the prev links on the node that used to be self.nil.next correctly. However, I think his solution is not ideal. Here's what I suggest instead:
Here's the immediate fix to the issue:
def addNode(self, v):
a = Node(v)
a.setNext(self.nil.next)
self.nil.next.setPrev(a) # this is the link that was previously missing
a.setPrev(self.nil)
self.nil.setNext(a)
However, that won't work correctly when the list is empty, since self.nil.next is None at the start. We can fix it though, by making self.nil link to itself when we create it in the List constructor:
def __init__(self):
self.nil = Node(None)
self.nil.next = self.nil.prev = self.nil # set up circular links!
Now, self.nil will always have a valid node as it's next and prev values.
You will need to change your removeNode and printList loops to check for self.nil rather than None.

The bug is in your addNode function, the .prev node for all of your nodes is self.nil
Using the following:
def addNode(self,v):
a = Node(v)
a.setNext(self.nil.next)
if self.nil.next is not None:
self.nil.next.setPrev(a)
a.setPrev(self.nil)
self.nil.next = a
will fix your problem. You probably want to put this logic in the setPrev and setNext functions (to make sure a == a.next.prev and a == a.prev.next at all times for all a except the ends).

Related

How can I use the test ive created to debug the code below ? What do I need to change in the code?

Ive made the testers here and they work fine in diagnosing the bug.
Heres the code for linked_list_from_list
def linked_list_from_list(items):
ll = LinkedList()
for i in items:
ll.add_value(i)
return ll
def test_empty():
ll = LinkedList()
assert ll.count_of(1) == 0
def test_zero():
ll = linked_list_from_list([1,2,3])
assert ll.count_of(0) == 0
def test_one():
ll = linked_list_from_list([1,2,3])
assert ll.count_of(2) == 1
def test_two():
ll = linked_list_from_list([1,2,2,3])
assert ll.count_of(2) == 2
def test_bug():
ll = linked_list_from_list([1,2,3])
assert ll.count_of(1) == 4
def test_small():
ll = linked_list_from_list([1])
assert ll.count_of(1) == 1
def test_bug():
ll = linked_list_from_list([1,2,3])
assert ll.count_of(1) == 4
def test_small():
ll = linked_list_from_list([1])
assert ll.count_of(1) ==
and the results show an assertion error
but I don't know what to change in the main block of code here :
class LinkedList:
"""Stores data using a linked list"""
def __init__(self):
"""Create a new, empty linked list"""
self.head = None
def add_value(self, value):
"""Add a new value to the head of the list
:param value: the new value to store"""
self.head = ListNode(value, self.head)
def count_of(self, value):
"""Counts the number of occurrences of value in the list
:param value: the value to count
:returns: the number of occurrences of value in the list"""
cursor = self.head
count = 0
if self.head is None:
return 0
while cursor.nextNode is not None:
if cursor.value == value:
count += 1
cursor = cursor.nextNode
return count
I know its something to do with the count_of function where in the case where there's a count of the digit 1 it returns 4.

Implementing append function in linked list in python

I am trying to write the list.append() operation in python. I implemented a linked list and it work fine. But I am not getting the last data item to be printed. When I try to print all the items in the list I get all the data value inside the node printed except the last one. I get 'None' printed instead of the value. I'm making some mistake in assigning the next pointer to 'None' in the newly added node. Need help in fixing.
Implementation of Node class and List class.
class Node:
def __init__(self,item):
self.data = item
self.next = None
def getData(self):
return self.data
def getNext(self):
return self.next
def setData(self,newItem):
self.data = newItem
def setNext(self, newNext):
self.next = newNext
class UnorderedList:
def __init__(self):
self.head = None
def isEmpty(self):
return self.head == None
def add(self,item):
temp = Node(item)
temp.setNext(self.head)
self.head = temp
def size(self):
count = 0
current = self.head
while current != None:
count = count + 1
current = current.getNext()
def append(self, item):
current = self.head
isEnd = False
newItem = Node(item)
while not isEnd:
if current.getNext() == None:
isEnd = True
else:
current = current.getNext()
current = current.setNext(newItem)
newItem = current.getNext()
def printList(self):
current = self.head
isEnd = False
while not isEnd:
if current.getNext() == None:
isEnd = True
else:
print current.getData()
current = current.getNext()
I create an object and pass values.
mylist = UnorderedList()
mylist.add(31)
mylist.add(77)
mylist.add(17)
mylist.add(93)
mylist.add(26)
mylist.add(54)
print(mylist.size())
mylist.append(12)
print(mylist.size())
mylist.append(15)
print(mylist.size())
print('\n')
print mylist.printList()
Output is:
6
7
8
54
26
93
17
77
31
12
None
The problem is you are doing
print(mylist.printList())
while printList() doesn't actually return anything. That's the last None printed there.
Hope this helps:
current = self.head
while(current!=None):
print(current.getData())
current=current.getNext()
This should be placed inside printlist.
And called this way :
mylist.printlist()
54
26
93
17
77
31
12
15
Edit :
I had also modified your append function to :
def append(self, item):
print("append",item)
current = self.head
isEnd = False
newItem = Node(item)
while not isEnd:
if current.getNext() == None:
isEnd = True
else:
current = current.getNext()
print("\Appending to",current.getData())
current.setNext(newItem)
current=current.getNext()
print("\tAppended",current.getData())

Append method for linked list

class _ListNode:
def __init__(self, value, next_):
self._data = value
self._next = next_
return
class List:
def __init__(self):
self._front = None
self._count = 0
return
def _linear_search(self,key):
previous = None
current = self._front
index = 0
while current is not None and key > current._data:
previous = current
current = current._next
index += 1
if current._data != key:
previous = None
current = None
index = -1
return previous, current, index
def __contains__(self, key):
_, _, i = self._linear_search(key)
return i != -1
def append(self, value):
if self._front is None:
self._front = _ListNode(value,None)
else:
self._front._next = _ListNode(value,None)
self._count += 1
l = List()
lst = [1,2,3,4]
i = 0
n = len(lst)
while i < n:
l.append(lst[i])
i += 1
print("{}".format(l.__contains(3))
To explain more, I implement the linear search method and the contains method. The contains method check if the number is in the list or not (returns true or false). Now when I need to check that #3 in the list using contains method, the answer is false!! i cant know what's the problem
Your append method does not walk down the list. It simply always appends to self._front._next if self.front is already present. Meaning the contents at the end of the append loop are the first thing you appended, the last thing you appended and nothing in between.
To correct it walk the list looking for a _next equal to None and append there.
def append(self, value):
if self._front is None:
self._front = _ListNode(value, None)
else:
n = self._front
while n._next is not None:
n = n._next
n._next = _ListNode(value, None)
self._count += 1
You could also define a _str__ method to print the content of the List
e.g.
def __str__(self):
res = []
n = self._front
while n is not None:
res.append(str(n._data))
n = n._next
return ', '.join(res)
This is not a particularly efficient implementation as it builds an intermediate builtin list object.
You also don't need those bare return statements in your methods. You can remove those.

Sometimes None is printed - and sometimes it doesn't, can't get why?

I got this school assignment, here is my code:
class Doubly_linked_node():
def __init__(self, val):
self.value = val
self.next = None
self.prev = None
def __repr__(self):
return str(self.value)
class Deque():
def __init__(self):
self.header = Doubly_linked_node(None)
self.tailer = self.header
self.length = 0
def __repr__(self):
string = str(self.header.value)
index = self.header
while not (index.next is None):
string+=" " + str(index.next.value)
index = index.next
return string
def head_insert(self, item):
new = Doubly_linked_node(item)
new.next=self.header
self.header.prev=new
self.header=new
self.length+=1
if self.tailer.value==None:
self.tailer = self.header
def tail_insert(self, item):
new = Doubly_linked_node(item)
new.prev=self.tailer
self.tailer.next=new
self.tailer=new
self.length+=1
if self.header.value==None:
self.header = self.tailer
it builds a stack, allowing you to add and remove items from the head or tail (I didn't include all the code only the important stuff).
When I initiate an object, if I return self.next it prints None, but if I return self.prev, it prints nothing, just skips, I don't understand why since they are both defined exactly the same as you see, and if I insert only head several times for example for i in range(1,5): D.head_insert(i) and then I print D it prints 5 4 3 2 1 None but if I do tail insert for example for i in range(1,5): D.tail_insert(i) and print D it prints 1 2 3 4 5"as it should without the None. Why is that?
I have included an image:
Keep in mind that you create a Deque which is not empty. You're initializing it with a Node with value None
You're interchanging the value and the Node object. When you're checking if self.tailer.value==None: it's probably not what you're meaning
Following to point 2 is a special handling for the empty Deque, where header and tailer is None
Here is what I have in mind, if I would implement the Deque. I'm slightly changed the return value of __repr__.
class Deque():
def __init__(self):
self.header = None
self.tailer = None
self.length = 0
def __repr__(self):
if self.header is None:
return 'Deque<>'
string = str(self.header.value)
index = self.header.next
while index!=None:
string+=" " + str(index.value)
index = index.next
return 'Deque<'+string+'>'
def head_insert(self, item):
new = Doubly_linked_node(item)
new.next=self.header
if self.length==0:
self.tailer=new
else:
self.header.prev=new
self.header=new
self.length+=1
def tail_insert(self, item):
new = Doubly_linked_node(item)
new.prev=self.tailer
if self.length==0:
self.header=new
else:
self.tailer.next=new
self.tailer=new
self.length+=1
Following Günthers advice, I have modified the __repr__ to this:
def __repr__(self):
string = str(self.header.value)
index = self.header
while not (str(index.next) == "None"):
string += (" " + str(index.next.value))
index = index.next
return string
that did solve the problem, but it is the ugliest solution I have ever seen.
does anyone know a better way?
Following to the question of a better __repr__ method here my proposal. Extend the Deque class with an __iter__ method. So you can iterate over the Deque which is nice to have, e.g.:
for item in D:
print item
Based on that the __repr__ method is easy. Here is the whole change:
def __repr__(self):
return 'Deque<'+' '.join([str(item.value) for item in self])+'>'
def __iter__(self):
index=self.header
while index is not None:
yield index.value
index=index.next

Use a function built outside the class on an object in Python?

I have a class
class List:
def __init__(self,head,tail):
self.head = head
self.tail = tail
def cons(self,item):
return List(item,self)
def isEmpty(self):
return self.head == None
def display(self):
s = "["
first = True
list = self
while not list.isEmpty():
if not first:
s=s+","
first = False
s=s+str(list.head)
list = list.tail
s=s+"]"
return s`
which creates a List object. I have a function (not sure if it works yet);
def sorted(list):
sort = False
i = 0
while i < range(len(list))+1:
if list[i] < list[i+1]:
sort = True
return sort
else:
return sort
and I want to run this function on the List object without adding another method to the class. I know if this was in the class it would just be List.sorted() but how can I run this function on the object without it being the objects method?
sorted(List) doesn't seem to work either. Help please.
Please, please, PLEASE: don't use sorted as a function name. There is a standard (built-in) function sorted() already, that returns a sorted version of an iterable.
Given that your code just checks to see if the List is in order, perhaps you could call it in_order or ordered or is_ascending instead?
That said, let's try to get your code working:
class Node:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
class List:
def __init__(self, head:Node=None, tail:Node=None):
self.head = tail if head is None else head
self.tail = head if tail is None else tail
def cons(self, node:Node):
node.next = self.head
return List(node, self.tail)
def isEmpty(self):
return self.head == None
def display(self):
return str(self)
def __str__(self):
result = "["
first = True
n = self.head
while n is not None:
if not first:
result += ", "
result += str(n)
if n == self.tail:
break
n = n.next
first = False
result += "]"
return result
def ascendingp(self) -> bool:
n = self.head
last = None
while last != self.tail:
if last is not None and not last.data < n.data:
return False
last = n
n = n.next
return True
tests = (
(1,2,3),
(1,3,2),
(),
)
for t in tests:
last = None
first = None
for i in reversed(t):
n = Node(data=i)
first = n if first is None else first
n.next = last
last = n
l = List(head=last, tail=first)
print(str(l), "Ascending?", l.ascendingp())

Categories