I'm a python/programming newb, and I am self-learning python. Unfortunately I'm really stuck! I'm in chapter 19 of "How to Think Like a Computer Scientist".
The object here is to write an implementation of a Priority Queue ADT, using a linked list.
I'm getting an error at lines 22 and 32. My understanding of this error, is that one or more of my node objects do not have the attribute "cargo". I don't understand this, as all of my node objects are assigned a cargo of "None", or some number, when they are created. The node object is written as it was given in the book.
I should mention, that LINE 31 works FINE. I only have a problem when I add LINE 32, which calls LINE 22 (which is apparently where the problem is hiding) that I get an error.
Any insight would be helpful. Thank you so much!!!
I reproduced the problem on a smaller scale:
class Node:
def __init__(self, cargo= None, next = None):
self.cargo = cargo
self.next = next
class Priority_Queue_For_Linked():
def __init__ (self):
self.max = None
self.nextmax = None
self.min = None
self.length = 0
def insert (self, cargo):
node = Node(cargo)
if self.length == 0:
node = self.max = self.min
self.length = 1
return
if node.cargo > self.max.cargo: # <--LINE 22
notmaxanymore = self.max
notmaxanymore.next = node
node = self.max
self.nextmax = notmaxanymore
self.length += 1
return
testlist = Priority_Queue_For_Linked()
testlist.insert(12)
testlist.insert(22) # <--LINE 32
And here is the error:
=== RESTART: /Users/Desktop/Programming Career/Untitled6.py ===
Traceback (most recent call last):
File "/Users/Desktop/Programming Career/Untitled6.py", line 31, in <module>
testlist.insert(22)# <--line 32
File "/Users/Desktop/Programming Career/Untitled6.py", line 21, in insert
if node.cargo > self.max.cargo:# <--line 22
AttributeError: 'NoneType' object has no attribute 'cargo'
I doubt you need more context, but in case it helps, here is all of the code:
class Node:
def __init__(self, cargo= None, next = None):
self.cargo = cargo
self.next = next
def __str__(self):
return str(self.cargo)
def print_backward (self):
if self.next != None:
tail = self.next
tail.print_backward()
print self.cargo,
def print_list(node):
while node:
print node,
node = node.next
print
class Priority_Queue_For_Linked():
def __init__ (self):
self.max = None
self.nextmax = None
self.min = None
self.length = 0
def is_empty (self):
if self.length == 0:
print "List is empty."
def insert (self, cargo):
node = Node(cargo)
if self.length == 0:
node = self.max = self.min
self.length = 1
return
if node.cargo > self.max.cargo:########40
notmaxanymore = self.max
notmaxanymore.next = node
node = self.max
self.nextmax = notmaxanymore
self.length += 1
return
if node.cargo < self.min.cargo:
notminanymore = self.min
node.next = notminanymore
node = self.min
self.length += 1
return
else:
comparisonnode = self.min.next
comparisonprev = self.min
for i in range (2, self.length):
if node.cargo < comparisonnode.cargo:
node.next = comparisonnode
comparisonprev.next = node
self.length += 1
break
comparisonnode = comparisonnode.next
comparisonprev = comparisonprev.next
def remove (self):
maxtoremove = self.max
self.max = self.nextmax
self.max.next = None
length -=1
return maxtoremove.cargo
def print_list(self):
tempnode = self.min
print "[",
while not tempnode == None:
print tempnode,
tempnode = tempnode.next
print "]"
testlist = Priority_Queue_For_Linked()
testlist.insert(12)
testlist.insert(22)#######86
When you insert your first item you have a problem in your assignments:
if self.length == 0:
node = self.max = self.min
self.length = 1
return
This will not change the value of self.max or self.min and they will stay as None, which of course won't have cargo. You also lose the node you are trying to add. I assume you wanted to do this:
self.max = self.min = node
The max attribute of the Priority_Queue_For_Linked class is defined as None in the __init__ method, and isn't changed before that if statement.
I presume you intended to assign a Node as the value of that attribute at some point, but you haven't done so.
You code tries to do self.max.cargo. In your __init__, you set self.max to None, and you never change this value anywhere else, so self.max is None. If you want to be able to use self.max, you need to set it to a real node value at some point.
Related
How can we get the previous and next item of a list in python? My code isn't working as it was supposed to. It always returns me 0th index of list. I dont want to use loop in this method.
Here's my code:
def provide_activetab_index(self,index):
if index > 0:
return index -1
if index < len(self.activetabs) - 1:
return index + 1
When i call this method it returns 0 when the self.current is 0.
def next(self):
index = self.provide_activetab_index(self.current+1)
self.display(self.frames[index])
def previous(self):
index = self.provide_activetab_index(self.current-1)
self.display(self.frames[index])
def next(self):
index = self.provide_activetab_index(self.current,1)
self.display(self.frames[index])
def previous(self):
index = self.provide_activetab_index(self.current,-1)
self.display(self.frames[index])
def provide_activetab_index(self,index,new):
if (index >= 0 and new == 1 and index < len(self.activetabs)-1) or (new == -1 and index > 0 and index < len(self.activetabs)):
return index + new
return index
EDIT
def provide_activetab_index(self,index,new):
l = len(self.activetabs)-1
if index >= l and new == 1:
return 0 # Return fist element if no last element
if index <= 0 and new == -1:
return l # Return last element if no previous element
else:
return index + new
To update self.current everytime
def next(self):
self.current = self.provide_activetab_index(self.current,1)
self.display(self.frames[self.current])
def previous(self):
self.current = self.provide_activetab_index(self.current,-1)
self.display(self.frames[self.current])
Hi i couldn't understand what you want exactly because there are few inputs that i don't know like self.current or self.activetabs so it is hard to modify your algorithm but there is data structure called "doubly_linked_list" you can implement that easily and than go to next or prev item with itemname.next or itemname.prev.Here is code
class Node:
def __init__(self, data, next_n=None, prev_n=None):
self.data = data
self.next = next_n
self.prev = prev_n
class Doubly_linked_list:
def __init__(self):
self.size = 0
self.root = None # points last member added
self.last = None # points first member added first member added is accepted as last member end next is None
def add(self, data):
if self.size == 0:
new_node = Node(data)
self.root = new_node
self.last = new_node
else:
new_node = Node(data)
new_node.next = self.root
self.root.prev = new_node
self.root = new_node
self.size += 1
def remove(self, data):
this_node = self.root
while this_node is not None:
if this_node.data == data:
if this_node.next is not None:
if this_node.prev is not None:
this_node.prev.next = this_node.next
this_node.next.prev = this_node.prev
else:
this_node.next.prev = None
self.root = this_node.next
else:
this_node.prev.next = None
self.last = this_node.prev
self.size -= 1
return True
else:
this_node = this_node.next
return False
def find_all(self, data):
this_node = self.root
while this_node is not None:
if this_node.data == data:
return data
elif this_node.next is None:
return False
else:
this_node = this_node.next
def print_all(self):
if self.root is None:
return None
this_node = self.root
print(this_node, end="-->")
while this_node.next != self.root:
this_node = this_node.next
print(this_node, end="-->")
print()
if you insist on finding nodes with indexes you can create a list object inside doubly_linked_list class inside init function self.list = [] and add all the nodes also to self.list and reach them by indexes.
With your code
def provide_activetab_index(self,index):
if index > 0:
return index -1
if index < len(self.activetabs) - 1:
return index + 1
when you pass index greater that 0 it will always return index-1.
As you mentioned self.current is 0 and you call it with
def next(self):
index = self.provide_activetab_index(self.current+1)
self.display(self.frames[index])
you actually calling
index = self.provide_activetab_index(1)
so this returns you 1-1 = 0
Assigned to design a linked list class from scratch using a generator to iterate through the list, but I've had a problem debugging this issue:
class LinkedList:
def __init__(self, data = None):
self.node = Node(data)
self.first = self.node
self.last = self.node
self.n = 1
def append(self, data = None):
new = Node(data)
self.last.next = new
self.last = new
self.n += 1
def __iter__(self):
self.index = self.first
return self.generator()
def generator(self):
for i in range(0, self.n):
yield self.index
self.index = self.index.next
One of the tests that the current generator passes is:
for n in a:
print n
# which should and does output
0
1
2
However, it fails to output the proper values in this case
for n in a:
if n == 2:
break
else:
print n
# Outputs 0 1 2, instead of:
0
1
I think my understanding of generators is lacking, and would love any help you guys have to offer!
Your shouldn't use n == 2 as the break-condition.
Try this:
# Assume your defined class `Node.py` like this:
class Node:
def __init__(self, data=None):
self.val = data
self.next = None
# I didn't modify your `LinkedList.py`
class LinkedList:
def __init__(self, data=None):
self.node = Node(data)
self.first = self.node
self.last = self.node
self.n = 1
def append(self, data=None):
new = Node(data)
self.last.next = new
self.last = new
self.n += 1
def __iter__(self):
self.index = self.first
return self.generator()
def generator(self):
for i in range(0, self.n):
yield self.index
self.index = self.index.next
if __name__ == '__main__':
ass = LinkedList(0)
ass.append(1)
ass.append(2)
ass.append(3)
for n in ass:
if n.val == 2: # Notice here
break
else:
print(n.val) # And here
I am working on a doubly linked list and I can't get my remove function to work correctly. I want to return the value that it is being removed. I have tried various times, with no success. An extra pair of eye would be appreciated.
class DoublyLinked_List:
class __Node:
def __init__(self, val):
self.val = val
self.next = None
self.prev = None
def __init__(self):
self.__header = self.__Node(None)
self.__trailer = self.__Node(None)
self.__header.next = self.__trailer
self.__trailer.prev = self.__header
self.__size = 0
def __len__(self):
return self.__size
def remove_element_at(self, index):
if index > self.__size or index < 0 or index == self.__size:
raise IndexError
current = self.__header.next
if index == 0:
self.__header.next = self.__header.next.next
else:
for i in range(0, index-1):
current = current.next
current.next = current.next.next
self.__size -= 1
return current.val
I am a rookie python programmer. I see the leetcode's definition of a linked list below. I got 2 questions for this concept, any help would be appreciated. Thanks in advance
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
Q1 Just wonder what is the type of the "self.next", I know in C++, it should be a pointer that represents the address of the next node. But python does not have that type, so I am confused what type "next" is.
Q2 Some tell me next is just a name. If that is the case, I run the code below,
head =ListNode(1)
print sys.getsizeof(head)
head.next = ListNode(2)
print sys.getsizeof(head)
first the head.next is 'None', and then it is assigned to another ListNode type,
but I get the same size of head before and after this change, which I think the size of head should be larger since one of its member (next) is changed from None type to ListNode type. I am just confused about this, thank you so much!
PS. In my understanding, if I keep adding new nodes to the linklist, the head will be larger and larger since there are more and more 'nested' member 'next', just point out where I get wrong, thanks.
Question 1:
Python variables are dynamically typed. (i.e. a variable could hold an int, and then hold a list, and then any other arbitrary object, etc).
In your case, Head.next starts by referencing, None a NoneType object.
After you assign it a different value (ListNode(2)), the Head.next now references the newly created ListNode object.
Question 2:
Why doesn't the size change.
I'm not an expert on how python's sys.getsizeof works, but from what I can gather, is that List.next in both cases is a reference variable (i.e. a variable that references some other object). The size doesn't change because sys.getsizeof finds the size of the object's variables. Where Head.next is just a reference to some other object in both cases.
See, How do I determine the size of an object in Python?, for more complete answers on how sys.getsizeof works.
My interpretation of a linked list.
class LinkedList(object):
class Node(object):
def __init__(self, val=None, next=None, previous=None):
self.val = val
self.next = next
self.last = previous
def __init__(self):
self.length = 0
self.start = None
self.end = None
def append(self, value):
self.length += 1
if not self.start:
self.start = self.Node(value)
else:
if not self.end:
self.end = self.Node(value)
self.end.previous = self.start
self.end.next = self.start
self.start.next = self.end
else:
end = self.Node(value)
self.end.next = end
end.previous = self.end
self.end = end
self.end.next = self.start
def prepend(self, value):
self.length += 1
if not self.start:
self.start = self.Node(value)
else:
n = self.Node(value, self.start, self.end)
self.start.previous = n
self.start = n
def __len__(self):
return self.length
def __iter__(self):
self.position = 0
return self
def next(self):
self.position += 1
if self.position-1 >= len(self):
raise StopIteration
if self.position-1 == 0:
return self.start
cnt = 0
n = self.start
while cnt<self.position-1:
n = n.next
cnt += 1
return n
def __getitem__(self, index):
if index == 0:
return self.start
if index == -1:
return self.end
cnt = 0
n = self.start
while cnt<index+1:
n = n.next
cnt += 1
return n.val
def __repr__(self):
return repr(tuple(x.val for x in self))
l = LinkedList()
l.append(4)
l.append(5)
l.append(3)
l.prepend(0)
print l
print l[1]
for my assignment I'm supposed to make a deque class that lets people insert from the front and the back, and also be able to remove from both the front and back, those are 4 separate functions in the Deque class.
If I use insert_front, then I can remove everything from the queue using remove_front, but if I use insert_front and try to use remove_rear, then my program breaks after doing remove_rear one time, it will remove the rear, but if I try to remove the next rear, the program breaks because there it doesn't know what the next rear node is, I have no idea how to be able to track both the front and rear so I can use these functions interchangeably. This also happens vice versa, with insert_rear and remove_front.
my code for the Deque class is as follows:
def insert_front( self, value ):
if self._rear==None and len(self)==1:
node = _DequeNode(value, self._front,self._rear)
self._front = node
self._rear=node
else:
node = _DequeNode(value, self._front,self._rear)
self._front = node
self._size += 1
return
def insert_rear( self, value ):
node = _DequeNode(value, self._front,self._rear)
self._rear = node
if self._front==None and len(self)==2:
self._front=node
self._size += 1
return
def remove_front( self ):
if self.is_empty():
value = None
else:
current = self._front
value = current._value
self._front = current._next
self._size -= 1
return value
def remove_rear( self ):
if self.is_empty():
value = None
else:
current = self._rear
value = current._value
self._rear = current._prev
self._size -= 1
return value
and this is my _DequeNode class:
def __init__(self, value, next_node,prev_node):
self._value = copy.deepcopy(value)
self._next = next_node
self._prev = prev_node
return
I definitely did something wrong while altering the code, because this was originally for a linked list, where you can only remove and insert from the front, and the teacher asked us to make it into a Deque that has both front and rear, I edited the code based on what I thought was supposed to happen..
Can someone please help me with this? I've been trying to figure this out for the entire day!
Thanks in advance!!
Here is a working version I wrote up real quick.
Also I added a __repr__ method so you could see what's happening (this isn't actually a good practice for a __repr__ unless you also modify the __init__ to be capable of taking the output as an argument.
You may also want to take a look at https://github.com/python-mirror/python/blob/master/Modules/_collectionsmodule.c - which contains the python deque implementation.
class DQ:
def __init__(self):
self._front = self._rear = None
self._size = 0
def insert_front( self, value ):
self._front = DequeNode(value, prev=self.front)
if self.size > 0:
self.front.prev._next = self._front
else:
self._rear = self._front
self._size += 1
def insert_rear( self, value ):
self._rear = DequeNode(value, next=self.rear)
if self.size > 0:
self.rear.next._prev = self._rear
else:
self._front = self._rear
self._size += 1
def pop_front( self ):
if self.empty:
raise IndexError("deque is empty")
else:
ret = self._front
self._size -= 1
self._front = self._front.prev
if self.front:
self.front._next = None
if self.size == 0:
self._front = None
return ret
def pop_rear( self ):
if self.empty:
raise IndexError("deque is empty")
else:
ret = self._rear
self._size -= 1
self._rear = self._rear.next
if self.rear:
self.rear._prev = None
if self.size == 0:
self._front = None
return ret
#property
def empty(self):
return self._size == 0
#property
def size(self):
return self._size
#property
def front(self):
return self._front
#property
def rear(self):
return self._rear
def __str__(self):
cur = self.rear
l = []
for i in range(self.size):
l.append(cur)
cur = cur.next
return str(l)
def __repr__(self):
return self.__str__()
class DequeNode:
def __init__(self, value=None, next=None, prev=None):
self._value = value
self._next =next
self._prev = prev
#property
def prev(self):
return self._prev
#property
def next(self):
return self._next
def __str__(self):
return str(self._value)
def __repr__(self):
return str("DequeNode( %s )" %self._value)