Linked lists with more than one value per node - python

I am trying to implement a doubly linked list with multiple variables (in this case two) per node in Python 3.
First, I created a HashEntry class for it (I'll get to make after this a hash table):
class HashEntry(self):
def __init__(self, key, data, p, n):
self.key = int(key)
self.data = str(data)
self.prev = n
self.next = p
Then I have to use this class for my doubly linked list operations and so, but I'm not sure how to do it, if I have to create another Node class or if I to put the two values for each method
This is what I have tried:
class Node:
def __init__(self, h = HashEntry, p = None, n = None):
# this is where i don't know how to put my hashentry type element
# into the node. i was trying to make it into a single element node.
self.element = h
self.next = n
self.prev = p
class Dlist(self):
def __init__(self):
self.head = None
self.last = None
def insert(self, e):
aux = Node(e, None, None)
if self.head is None:
self.head = self.last
self.head = aux
else:
aux.prev = self.last
aux.next = None
self.last.next = aux
self.last = aux
Thank you a lot.

Except the missing part of HashEntry management, the source code is showing some errors which not allow to execute the software.
Minor Error 1 - a Python class doesn't inherit from self and it is recommended to inherit from the class object.
Class declaration should be:
class HashEntry(object):
class Dlist(object):
Instead of:
class HashEntry(self):
class Dlist(self):
Minor Error 2 - a mixture between self.head and self.last when inserting the first HashEntry in the first linked-list.
The assignment self.head = self.last doesn't work because self.last is not initialize.
aux = Node(e, None, None)
if self.head is None:
# self.head = self.last <= wrong assignement
self.head = aux
self.last = self.head # assign last based to the head
else:
Analysis 1 - add the HashEntry management by using the key.
To create a double linked-list with the simulated hashtable access, the first linked-list has to manage a kind of hashtable and the second linked-list is linked to the first to store all nodes having the same key.
1- Add to the class Dlist a search(self,key) function to check if the key of the node aux = Node(e, None, None) exists in the first linked-list:
The returned value is the HashEntry node of the key otherwise
None.
def search(self,key):
curr = self.head
while (curr is not None):
if (key == curr.element.key):
return (curr)
curr = curr.next
return (None)
2- Add to the class Node a append(self,nwnode) function to add to the second linked-list the node nwnode having the HashEntry.key.
The second list has to header the node element.
def append(self,nwnode):
if (self.element.next is None):
self.element.next = nwnode # adding the first homo-key
nwnode.element.prev = self
else:
curr = self.element.next
while (curr.next is not None):
curr = curr.next
curr.next = nwnode # adding others homo-key
nwnode.element.prev = curr
3- Connect both functions in the insert(self, e) of the class Dlist.
Check if the key is existing when the first linked-list is not
empty.
else:
hashnode = self.search(e.key)
Then insert the new HashEntry aux node in the first linked-list or append it to the second linked-list.
if (hashnode is None):
aux.prev = self.last
aux.next = None
self.last.next = aux # insert to the first linked-list
self.last = aux
else:
hashnode.append(aux) # append to the second linked-list

Related

why am not able to display data if inserting a new node in a empty circular lined list?

Below is the code snippet to add node in two scenario
if the circular linked list is empty
Add node at the end of the circular linked list
class Node:
def __init__(self, data):
self.data = data
self.start = None
class cLL:
def __init__(self):
self.start = Node(None)
self.last = Node(None)
self.start.nxt = self.last
self.last.nxt = self.start
def addEmpty(self, val):
nu = Node(val)
if self.start.data == None:
self.start = nu
self.last = nu
nu.nxt = self.start
return nu
def addEnd(self, val):
nu = Node(val)
if self.start == None:
print("no nodes at the beginning")
else:
self.last.nxt = nu
self.last = nu
nu.nxt = self.start
def display(self):
tmp = self.start
while tmp.nxt != self.last.nxt:
tmp = tmp.nxt
print(tmp.data)
rew = cLL()
rew.addEmpty(23)
rew.addEnd(30)
rew.addEnd(90)
rew.addEnd(900)
rew.display()
But the function "addEmpty()" is not working. The display function is not able to show it. Please suggest
Several issues:
A circular list should not be initiated with two nodes (having None as data), but with no nodes.
When adding a node to an empty list, you should not assign that node reference to both start and last, as that gives you a duplicate node for no good reason. If then later you mutate start, you'll be mutating the node that also last references, and vice versa. This will almost always have undesired effects.
A Node instance should not get a start attribute in its constructor, but should instead get an initialised nxt attribute.
The display method is printing not printing the data of the start node, but it is printing the data of the last node. This is confusing. That function should display all node's data.
For a circular list you actually don't need both a start and last reference. Either the list is empty, or else the start node will always be the one referenced by last.nxt (if there are no errors). So that means you can do with only the last attribute and drop the start attribute. This will also save you some code.
It is not clear why you would have a different method for adding a node to an empty list, than for adding a node to a non-empty list. Just use one method and make the distinction with an if, which anyway you already have for checking the list is empty or not.
Here is a corrected version:
class Node:
def __init__(self, data):
self.data = data
# A node has a nxt attribute, not start.
# As a circular list NEVER has None-references, make this a self refence
self.nxt = self
class cLL:
def __init__(self):
self.last = None # Don't create a node here! No need for `start`
def addEnd(self, val): # One method, not two
nu = Node(val)
if self.last is None:
self.last = nu
else:
nu.nxt = self.last.nxt
self.last.nxt = nu
self.last = nu
def display(self):
if not self.last:
return # nothing to print
tmp = self.last.nxt
print(tmp.data)
while tmp != self.last:
tmp = tmp.nxt
print(tmp.data)
rew = cLL()
rew.addEnd(23)
rew.addEnd(30)
rew.addEnd(90)
rew.addEnd(900)
rew.display()
Your display function is incorrect, you are never printing the start value as you go to the next one before printing. An example answer would be to add a print statement before the while loop starts. Hope this helps:
def display(self):
tmp = self.start
print(tmp.data)
while tmp.nxt != self.last.nxt:
tmp = tmp.nxt
print(tmp.data)

I am trying to print the elements of linked list after adding it but it doesn't seem to work

I am trying to show the items in my linked list after inserting them with the function Add, and view function to print but it doesn't seem to work.
class Node():
def __init__(self,value):
self.value = value
self.next = None
class Linked_List():
def __init__(self):
self.head = None
self.tail = None
def Add(self,value):
if(self.head == None):
n = Node(value)
if(self.head == None):
self.head = n
else:
self.tail.next = n
self.tail = n
def view(head):
curr = head
while (curr):
print(curr.value,"-->")
curr = curr.next
newlist = Linked_List()
newlist.Add(5)
newlist.Add(6)
newlist.Add(56)
view(newlist.head)
It only shows the first element 5 and doesn't show the rest. I can't seem to understand the reason even if I have done acc. to the algorithm?
If head is not Null, Add doesn't do anything, which even the most rudimentary debugger would have made clear.

'AttributeError' in linked list in Python

This code deals with removal of duplicates from a linked list in Python. The problem seems to be in the remove function.
class Node(object):
def __init__(self, data = None, next_node = None):
self.next_node = next_node
self.data = data
#get data at that location
def get_data(self):
return self.data
#get next element in linked list
def get_next(self):
return self.next_node
#point to node specified by argument
def set_next(self, new_next):
self.next_node = new_next
class LinkedList(object):
def __init__(self, head = None):
self.head = head
#insert element in linked list
def insert(self, data):
new_node = Node(data)
new_node.set_next(self.head)
self.head = new_node
#remove duplicates
def remove(self):
#point to head
current = self.head
previous = None
removed = False
#variable to compare the current data with the rest
new = current
new = new.get_next()
#while current is not None
while current:
if current.get_data() != new.get_data():
previous = new
new = new.get_next()
#if same data, delete extra node from list
else:
removed = True
#if only one element in list
if previous is None:
self.head = new.get_next()
else:
previous.set_next(new.get_next())
new = new.get_next()
#if 'new' reaches end of list, do this
if new is None:
current = current.get_next()
previous = current
new = current
new = new.get_next()
if not removed:
print("No duplicates!")
#print resulting linked list
def print_result(self):
current = self.head
while current:
print(current.get_data(), end = " ")
current = current.get_next()
(I have ignored the 'function calling' part of the code).
I am getting an attribute error at the first if statement after while current: (in the remove function) saying:
Traceback (most recent call last):
File "python", line 64, in <module>
File "python", line 26, in remove
AttributeError: 'NoneType' object has no attribute 'get_data'
I can't understand which is None and why. Any help is greatly appreciated!
Your general approach appears correct, assuming you're OK with an exponential running time, but there are some details that will cause crashes. Here's a couple I spot offhand:
If the list is length 1, if current.get_data() != new.get_data(): will crash because new is None.
These lines:
current = current.get_next()
previous = current
new = current
new = new.get_next() # boom!
will crash when you reach the end of the list. current is the last node and you get the next, which is None, and then attempt to None.get_next().
To fix these, proceed through your list one node at a time and check for None every time you next to avoid crashing. Same goes for unlinking: only unlink one node at a time by keeping prev where it is and setting prev.next_node and curr to curr.next, then test if curr is None before doing anything else.
Here's a simple, working version:
def remove(self):
curr = self.head
while curr:
runner = curr.next_node
prev = curr
while runner:
if runner.data == curr.data:
prev.next_node = runner.next_node
else:
prev = runner
runner = runner.next_node
curr = curr.next_node
The idea is to use curr to step through the list node by node. For every node, create a runner and prev which will iterate through the remainder of the list node by node and unlink any nodes that match curr.
There's also a linear approach using a set (trading space for speed):
def remove_linear(self):
seen = set()
curr = self.head
prev = None
while curr:
if curr.data not in seen:
seen.add(curr.data)
prev = curr
else:
prev.next_node = curr.next_node
curr = curr.next_node
Try it!
A last note: Python generally doesn't use getters and setters; they add verbosity and don't offer any genuine protection, so I omitted them in my code above. Trust your client and use underscore prefixes for "private" variables.

Python Reverse a Linked List

I am doing a Python program that implements linked list to support a few functions, one of the functions I need to do is to reverse a stack. I have made a Node, LinkedList and Stack classes, here is my Code so far:
class ListNode:
def __init__(self, Object):
self.Object = Object
self.next = None
class LinkedList:
def __init__(self):
self.head = None # first node
self.tail = None # last node
def addLast(self, Object):
newNode = ListNode(Object)
if self.head == None:
self.head = newNode
self.tail = newNode
else:
self.tail.next = newNode
self.tail = newNode
def removeFirst(self):
if self.head == None:
return
self.head = self.head.next
if self.head == None:
self.tail = None
def removeLast(self, Object):
if self.head == None:
return
current = self.head
prev = None
while current.next != None:
prev = current
current = current.next
if prev == None:
self.head = None
self.tail = None
else:
prev.next = None
self.tail = prev
def get(self, index):
current = self.head
i = 0
while i < index and current != None:
current = current.next
i = i + 1
if current != None and index >= 0:
return current.Object
else:
return None
def size(self):
current = self.head
count = 0
while current != None:
count = count + 1
current = current.next
return count
def isEmpty(self):
return self.head == None
def printList(self):
if self.head != None:
current = self.head
while current != None:
print(current.Object, end = ' ')
current = current.next
print()
# -------------------- STACK ---------------------------------------------------
class Stack:
# constructor implementation
def __init__(self):
self.llist = LinkedList()
def front(self):
return self.llist.get(0)
def dequeue(self):
self.llist.removeFirst()
def queue(self, Object):
self.llist(Object)
def push(self, Object):
self.llist.addLast(Object)
def pop(self, Object):
self.llist.removeLast(Object)
def printStack(self):
self.llist.printList()
def size(self):
return self.llist.size()
def isEmpty(self):
return self.llist.isEmpty()
# ----------------------- Reverse LIST ------------------------------
def Reverse(S):
# S is a Stack Object
Here is my attempt at the problem:
def rRecursive( self ) :
self._rRecursive( self.head )
def _reverseRecursive( self, n ) :
if None != n:
right = n.next
if self.head != n:
n.next = self.head
self.head = n
else:
n.next = None
self._rRecursive( right )
def Reverse(S):
s.rRecursive()
If this was an ordinary list I could easily reverse it using [::-1] but I cannot since the linkedlist is an object. I was thinking maybe I could use temporary values so I can someone append the beginning of the stack to a list and then somehow convert it back into a stack object.
Edit for duplication: The goal of my program is use an existing Stack and reverse it. The linked post deals with a linked list that was already in a list format.
def get(self, index):
current = self.head
i = 0
while i < index and current != None:
current = current.next
i = i + 1
if current != None and index >= 0:
return current.Object
else:
return None
Edit 2: added my get function.
class Stack:
# constructor implementation
def __init__(self):
self.llist = LinkedList()
def front(self):
return self.llist.get(0)
# push method implementation
def push(self, Object):
self.llist.addLast(Object)
def pop1(self):
self.llist.removeLast1()
def Reverse(S):
new_stack = Stack()
while not S.isEmpty():
new_stack.push(S.front())
S.pop1()
return new_stack
# Current Stack after Push: 12 14 40 13
# Stack after Pop: 12 14 40
# Stack after Reversal: 12 12 12
Edit 3: Added a rework of my code, it returns back a wrong reversal with the first element over and over again.
It's quite easy to reverse a stack using basic stack operations. Pop each item off the old stack and push it onto a new one.
def reverse(stack):
new_stack = Stack()
while not stack.isEmpty():
new_stack.push(stack.front())
stack.pop()
return new_stack
You could do something similar to destructively reverse the LinkedList within the Stack while reusing the stack object itself, you'd just need to use the list operations rather than the stack operations that are aliased to them.
Speaking of stack operations, you'll probably find that your stack performs better if you push and pop from the front, rather than the back. Removing an item from the end of the linked list requires iterating over the whole list (to find the next-to-last node). In contrast, both adding and removing from the front are fast.
You shouldn't have to fiddle with link pointers in your reversal function. I assume that you have a pop() method and other basics with your stack; if not, then clone your removeFirst function to return the removed node.
Now, the recursive function is simple: pop the head of the list, reverse the remaining stack (if any), and add the popped node to the end. Does this handle your problem?
def reverseStack(self):
move_me = self.pop()
if not self.isEmpty():
return (self.reverseStack()).addLast(move_me)
else:
new_stack = Stack()
return new_stack.addLast(move_me)
Other approaches to solving this problem: Cheat.
Define a __iter__ method (which makes sense in any event; iteration is a core Python behavior) to make your type iterable. Simple example:
def __iter__(self):
cur = self.head
while cur is not None:
yield cur.Object
cur = cur.next
Then just do:
values = list(self) # Creates a list containing the current set of values
self.head = self.tail = None # Clear existing linked list
# Add back all the values in reverse order
for value in reversed(values):
self.addLast(value)
Sure, it's likely less efficient in memory allocation/deallocation overhead than doing it properly. But the effect is likely marginal, and it simplifies the implementation code dramatically.
Of course, doing it properly isn't that hard, it's just slightly more confusing (totally untested, but it should be close to right):
def reverse(self):
# Start at beginning, which will be new end
cur, last = self.head, None
# Reverse head and tail pointers in advance
self.head, self.tail = self.tail, self.head
# Traverse while reversing direction of each node pointer
while cur is not None:
# Tuple pack and unpack allows one-line variable swap
cur.next, cur, last = last, cur.next, cur
The usual algorithm for reversing things using basic data structures is to use the fact that a stack is a first in last out data structure. That means if you pop until the stack is empty, you will get the items in the opposite order you pushed them on.
But it looks like you want to do this via recursive functions rather than an explicit stack - in this case, your function would normally fetch the front element,then recurse on the rest of the data structure, then handle that first element. This gets all the elements off in order, but handles them in the opposite order as each recursive call finishes and you work your way back up the call stack. If you neex to add the elements to a reversed data structure (and not just print them), you can build it up via return values by noticing that once you have the reverse if everything after the current element, you just need to attach that element to the front and you have the reverse of everything you were handed.
class Node(object):
def __init__(self, data=None, next_node=None):
self.data = data
self.next = next_node
def Reverse(head):
if head == None :
return None
elif head.next == None :
return head # returns last element from stack
else :
temp = head.next # stores next element while moving forward
head.next = None # removes the forward link
li = Reverse(temp) # returns the last element
temp.next = head # now do the reverse link here
return li
def main() :
temp4 = Node(4,None)
temp3 = Node(3,temp4)
temp2 = Node(2,temp3)
head = Node(1,temp2)
res = Reverse(head)
while res != None :
print(res.data)
res = res.next
main()

Error when deleting a node in a Linked List <ListNode.ListNode object at 0x0000000267320>

I am making a linkedlist, and I had to add in some different functions such as max, min , count and index for my list. I now have to add a remove function which is this snippet of code.
def removeItem(self, position):
''' removeItem removes a selected, because python has a built in "garbage remover",
you don't have to physically delete the node, you only have to skip that node link and python will destroy it
by it self.'''
currentNode = self.head
previousNode = None
count = 0
while count != position:
#This is a quick check to make sure the next node isn't empty.
if currentNode.link is None:
print("Position Invalid")
return None
previousNode = currentNode
currentNode = currentNode.link
count += 1
#Node.Link should link to the next node in the sequence.
previousNode.link = currentNode.link
return currentNode
I am basically just trying to link over the next node in the sequence, so that the built-in garbage remover will remove that node from the sequence. However, I am getting the following error message, which I know has to do something with my instance.
C:\Python33\python.exe "C:/Users/koopt_000/Desktop/College/Sophomore Semester 2/Computer Science 231/Chapter4/Test.py"
900
1
1
2
<ListNode.ListNode object at 0x0000000002679320>
Process finished with exit code 0
Why is it printing out this weird ListNode.ListNode object at the end?
Here is my testing code:
from ListNode import ListNode
from LinkedList import LinkedList
node1 = ListNode(1)
node2 = ListNode(900)
node3 = ListNode(3)
node4 = ListNode(99)
node1.link = node2
node2.link = node3
node3.link = node4
linked_list = LinkedList((1, 900, 3, 99))
print(linked_list.__max__())
print(linked_list.__min__())
print(linked_list.getCount(900))
print(linked_list.getIndex(3))
print(linked_list.removeItem(3))
This is my code for my ListNode class:
# ListNode.py
class ListNode(object):
def __init__(self, item = None, link = None):
'''creates a ListNode with the specified data value and link
post: creates a ListNode with the specified data value and link'''
self.item = item
self.link = link
This is my code for my LinkedList class:
from ListNode import ListNode
class LinkedList(object):
#--------------------------------------------------------------
def __init__(self, seq=()):
""" Pre: Creates a Linked List
Post: Creates a list containing the items in the seq=()"""
if seq == ():
# If there is no items to be put into the list, then it creates an empty one.
self.head = None
else:
# Creates a node for the first item.
self.head = ListNode(seq[0], None)
# If there are remaining items, then they're added while keeping track of the last node.
last = self.head
for item in seq[1:]:
last.link = ListNode(item, None)
last = last.link
self.size = len(seq)
#-------------------------------------------------------------
def __len__(self):
'''Pre: Nothing.
Post: Returns the number of items in the list.'''
return self.size
#-------------------------------------------------------------
def __max__(self):
''' Goes through each node and compares what the max is for the linked list.
Post: Finds the max of the linked list and returns that value.'''
if self.head is None:
return None
max_value = self.head.item
node = self.head.link
while node is not None:
if node.item > max_value:
max_value = node.item
node = node.link
return max_value
#--------------------------------------------------------------
def __min__(self):
''' Goes through each node and compares what the min is for the linked list.
Post: Finds the min of the linked list and returns that value.'''
if self.head is None:
return None
min_value = self.head.item
node = self.head.link
while node is not None:
if node.item < min_value:
min_value = node.item
node = node.link
return min_value
#--------------------------------------------------------------
def getCount(self, yourData):
''' This function counts the amount of times a certain item is in the Linked List.'''
count = 0
node = self.head
for i in range(self.size):
data = node.item
if data is yourData:
count += 1
node = node.link
return count
#--------------------------------------------------------------
def getIndex(self, yourData):
''' getIndex finds the index of the selected item and returns that value. '''
node = self.head
if node is None:
return None
for i in range(self.size):
data = node.item
if data == yourData:
return i
node = node.link
raise IndexError
#--------------------------------------------------------------
def removeItem(self, position):
''' removeItem removes a selected, because python has a built in "garbage remover",
you don't have to physically delete the node, you only have to skip that node link and python will destroy it
by it self.'''
currentNode = self.head
previousNode = None
count = 0
while count != position:
#This is a quick check to make sure the next node isn't empty.
if currentNode.link == None:
print("Position Invalid")
return None
previousNode = currentNode
currentNode = currentNode.link
count += 1
#Node.Link should link to the next node in the sequence.
previousNode.link = currentNode.link
return currentNode
#--------------------------------------------------------------
If anyone could help me out to find out why my removeItem function isn't working that would be helpful!
On a side note, I'm also trying to make a doubly linked list of this list, I know I need to add a prev_node function into my ListNode function, but what else do I need to add? Thanks again!
If your method is returning a <LinkNode object at 0xmemoryaddr> string then it is working fine. You are printing the removed node, and Python is using the default repr() representation for that instance.
If you wanted to make it more readable, you could give the ListNode a object.__repr__ method:
def __repr__(self):
next = 'None' if not self.link else '...' # just to indicate
return 'ListNode({!r}, {})'.format(self.item, next)
This then will print ListNode(99, None) instead of the <ListNode object at 0xmemoryaddr> string Python defaulted to:
>>> ll = LinkedList((1, 900, 3, 99))
>>> ll.head
ListNode(1, ...)
>>> ll.head.link
ListNode(900, ...)
>>> ll.head.link.link
ListNode(3, ...)
>>> ll.head.link.link.link
ListNode(99, None)
One thing you do have to take into account: you need to adjust the length of the list too; on successful removal, subtract 1 from self.size.

Categories

Resources