Classes in Linked List not working - python

Got a schoolwork to do showroom with 2 classes: Car & Node, while Node data contain Car class with its data. Then I have to make a Linked list, should be doubly, but I think a simple should work as well, with Nodes containing Cars. The only function in Linked list is inserting a new Node with new Car. It should be sorted by price of cars upwardly.
Tried this, but it keeps telling me
TypeError: '<' not supported between instances of 'NoneType' and 'NoneType'
class Car:
def __init__(self, id = None, name = None, brand = None, price = None, active = None):
self.id = id
self.name = name
self.brand = brand
self.price = price
self.active = active
class Node:
def __init__(self, data):
self.next = None
self.data = Car()
class LinkedList:
def __init__(self):
self.head = Node(None)
def insertNode(self, car):
newNode = Node(car)
curNode = self.head
if self.head.data is None:
self.head = newNode
if newNode.data.price < curNode.data.price:
newNode.next = curNode
self.head = newNode
else:
while curNode.next is not None and curNode.next.data.price <= newNode.data.price:
curNode = curNode.next
newNode.next = curNode.next
curNode.next = newNode
db = LinkedList()
def init(cars):
for car in cars:
db.insertNode(car)
def add(car):
db.insertNode(car)
Did I miss something, 'cause I think it should be working.

In Node.__init__ you have the line self.data = Car() which creates a Car instance using the default values (which are all None). That means that the price of every Car in the list is None. Later, you are getting an exception when you try comparing prices with newNode.data.price < curNode.data.price because you can't compare None values.
You probably need to replace self.data = Car() with something else. It's not obvious to me from your current code where the car data is supposed to come from or what format it is in. If the cars sequence you're iterating over in the top level init function is a list of Car instances already, then you should probably just do self.data = data in Node.__init__. Otherwise you'll need to do something else to extract the car data and pass it to the Car constructor. You may also want to consider getting rid of the default arguments to Car.__init__, since it doesn't seem to make much sense to create a car without them.

I see several problems, mainly regarding type consistency, in your code. You should maybe rethink what exactly the class structure here is supposed to do, how to set the default values etc. Also: Do you want to have the nodes next variable to be another node?
Assuming the following: We have Cars. Each Car has a Name, Brand and pricetag. We want two cars to be connected by a Node. And we want lists that can hold nodes and allow us to insert a new Node. Insertion should happen such that the node hierarchy connects cars in ascending price value. Two neighboring nodes share one car. You could write this as something like:
class Car:
def __init__(self, name = " ", brand = " ", price = 0):
self.name = name
self.brand = brand
self.price = price
class Node:
def __init__(self,car1,car2):
assert type(car1) == type(car2) == Car
if car1.price > car2.price:
self.next = car1
self.current = car2
else:
self.next = car2
self.current = car1
class LinkedList:
def __init__(self,firstnode):
self.ListOfNodes = [firstnode]
def insertNode(self, car):
for i in range(0,len(self.ListOfNodes)):
curnod = self.ListOfNodes[i]
newnod = Node(car,car)
if car.price < curnod.current.price:
if i<len(self.ListOfNodes): #If its not the last node
newnod.next = curnod.current
if i>0: #If its not the first node, i.e. it has a predecessor
ListOfNodes[i-1].next = newnod.current
self.ListOfNodes.insert(i,newnod)
return
elif car.price < curnod.next.price:
newnod.current = curnod.current
curnod.current = car
self.ListOfNodes.insert(i,newnod)
return
newnod.current = self.ListOfNodes[-1].next #this is only reached if the price is higher than all before
self.ListOfNodes.append(newnod)
car1 = Car(name = "baby",brand= "honda", price = 1000)
car2 = Car(name = "yomomma",brand= "Benz", price = 10)
car3 = Car(name = "PussyWagon",brand= "Dodge", price = 100)
car4 = Car(name = "FakeTaxi",brand= "HellNah", price = 10000000)
car5 = Car(name = "LondonTaxi",brand= "ChumBucket", price = 1)
p = Node(car2,car1)
lst = LinkedList(p)
lst.insertNode(car3)
lst.insertNode(car4)
lst.insertNode(car5)
It's very generic but it should work.

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)

Unable to figure out which data structure to use for efficiency

I come from C background currently learning Python. My task is to create a general tree. The input to the program is in two passes. In the first pass I must collect the identity, name, role and dept of a person. In the second pass I get to know the parent of a node, the manager. So I must store the values transiently. In C I would typically use an array of structs or a linked list depending on the availability of the size information. But I am lost here in Python, not even sure if what I am doing is okay let alone efficient.
Thanks in advance,
Preeti.
if __name__ == "__main__":
# Have successfully created the tree and added nodes by hardcoding values as shown below in commented code
# create_tree = Tree()
# Tree.add_node(42, "Stephen", "Time Cone Radiation", "Black Hole")
# But unable to figure out how to store transient info and use it later to create the tree.
num = 8
list = []
backup_num = num
while num:
id, name, role, dept = raw_input().split()
num -= 1
list.append((id, name, role, dept))
while backup_num:
id, parent = raw_input().split()
backup_num -= 1
#For an id in the list above locate it, and call add_node.
# But not sure how and what is an efficient way.
This will give you a fare idea. Hope this helps.
class Tree():
def __init__(self):
self.length = 0
self.data = {}
def add_node(self, nodeid, name, role, dept):
obj = {}
obj["child"] = {"left": None, "right": None}
obj["parent_id"] = None
obj["name"] = name
obj["role"] = role
obj["dept"] = dept
self.data[nodeid] = obj
self.length += 1
return True
# which_one : Left or Right
def update_child_id(self, which_one, nodeid_parent, nodeid_child):
self.data[nodeid_parent]["child"][which_one] = nodeid_child
return True
def update_parent(self, nodeid, parent_id):
self.data[nodeid]["parent_id"] = parent_id
return True
def display_node(self, nodeid):
obj = self.data[nodeid]
print("Node:", nodeid)
print("Parent:", obj["parent_id"], ", Name:", obj["name"], ", Role: ", obj["role"], ", Dept: ", obj["dept"])
def display_child(self, nodeid):
print(self.data[nodeid]["child"].items())
# Main
test = Tree()
# Get the identity and then add here
node_id, name, role, dept = [42, "Stephen", "Time Cone Radiation", "Black Hole"]
test.add_node(node_id, name, role, dept)
# Get the parent id and add here
parent_id, parent = [6, "James"]
test.update_parent(node_id, parent_id)
test.display_node(42)
test.display_child(42)

Python: Dijkstra' algorithm

need a help with Dijkstra. I found a lot of codes on the internet, but I can't use any of them, because I'm not given a graph, but just lists of Vertexes & Edges into createGraph function. It's a homework and I gotta have some attributes in classes.
This is what I have:
class Vertex:
def __init__(self, id, name):
self.id = id
self.name = name
self.minDistance = float('inf')
self.previousVertex = None
self.edges = []
self.visited = False
class Edge:
def __init__(self, source, target, weight):
self.source = source
self.target = target
self.weight = weight
class Dijkstra:
def __init__(self):
self.vertexes = []
self.result = 0
def createGraph(self, vertexes, edgesToVertexes):
for i in range(len(vertexes)):
self.vertexes.append(vertexes[i])
for j in range(len(edgesToVertexes)):
if edgesToVertexes[j].source == vertexes[i].id:
vertexes[i].edges.append(edgesToVertexes[j])
def getVertexes(self):
return self.vertexes
def findMinID(self):
maxDistance = 1000000
curVertex = None
result = None
for i in range(len(self.vertexes)):
self.vertexes[i] = curVertex
if curVertex.visited is False and curVertex.minDistance < maxDistance:
curVertex = result
curVertex.minDistance = maxDistance
else:
pass
self.result = result
return
def computePath(self, sourceId):
start = None
end = None
road = None
while start is None:
if Vertex.id == sourceId:
start = Vertex
start.minDistance = 0
start.visited = True
for i in range(len(start.edges)):
start.edges[i].target = end
start.edges[i].weight = road
if road < end.minDistance:
end.minDistance = start.minDistance + road
end.previousVertex = start.id
else:
pass
self.findMinID()
self.computePath(self.result.id)
I'm still beginner so I tried to keep it simple, but it's not working as it raises error:
'type' object is not subscriptable
or:
AttributeError: type object 'Vertex' has no attribute 'id'
which makes absolutely no sense to me why.
I can use any help, thanks in advance!
When you put the line:
self.vertexes = Vertex
you are assigning the variable to the actual class. Probably what you wanted to do was make an empty list, as you append to it later:
self.vertexes = []
I would assume this is where the error comes from, as if you ever try to iterate over self.vertexes, you are iterating over the Vertex class, which is impossible and throws that error.
You also have later:
start = Vertex
Try initializing the start, like:
start = Vertex(sourceId, "vertex")
Also, the line before that you have
if Vertex.id == sourceId:
meaning that you might want to make the id variable in Vertex static:
class Vertex:
id = 0
def __init__(self, id, name):
self.id = id
id += 1
Some suggestions: class tutorial in python
Edit:
To find the vertex that has the id you want, use a filter:
start = None
for v in self.vertexes:
if v.id == sourceId:
start = Vertex(sourceId, v.name)
start.minDistance = 0
break

Dijkstra's Algorithm - wrong order of nodes in shortest path

I've been working on a school assignment, where I need to implement Dijkstra's algorithm. That wouldn't be too hard by itself but unfortunately, the automatic checking script disagrees with all of my implementations (I actually made like 8 different versions). All the initial data checking works correctly, only when the script generates random data, it differs. My path and script's path has the same distance, but different vertexes on the path. For example:
Teachers path: City2, City15, City16, City6,
Students path: City2, City15, City18, City0, City6,
I even contacted the teacher who just responded with "You have to use priority queue :-)" despite me using one (in fact, several implementations of one, from my own to heapq). Am I doing something wrong or is it the teacher script that's incorrect? I hope the code is self-commenting enough to be understandable. Thank you for any advice you can give me.
The algorithm is called on source vertex and computes shortest distance and path to every other connected node. If the vertex has same minDistance (ie. priority) as some that's already there, it should go in front of it, not after it.
class Node:
"""Basic node of the priority queue"""
def __init__(self, data, priority):
self.data = data
self.nextNode = None
self.priority = priority
self.id = data.id
class PriorityQueue:
"""Basic priority queue with add, remove and update methods"""
def __init__(self):
self.head = None
self.count = 0
def add(self, data, priority):
"""Adds data with priority in the proper place"""
node = Node(data, priority)
if not self.head:
self.head = node
elif node.priority <= self.head.priority:
node.nextNode = self.head
self.head = node
else:
checker = self.head
while True:
if not checker.nextNode or node.priority >= checker.nextNode.priority:
break
checker = checker.nextNode
node.nextNode = checker.nextNode
checker.nextNode = node
return 0
def remove(self, data):
"""Removes specified node and reconnects the remaining nodes, does nothing if node not found"""
checker = self.head
if not self.head:
return 0
if checker.id == data.id:
self.head = checker.nextNode
while True:
checker = checker.nextNode
if not checker or not checker.nextNode:
return 0
if checker.nextNode.id == data.id:
checker.nextNode = checker.nextNode.nextNode
break
return 0
def update(self, data):
"""Updates priority of existing node via removing and re-adding it"""
self.remove(data)
self.add(data, data.minDistance)
return 0
def getMin(self):
"""Returns the minimum priority data"""
min = self.head
return min.data
class Edge:
"""Edge of the graph, contains source, target and weight of line"""
def __init__(self, source, target, weight):
self.source = source
self.target = target
self.weight = weight
class Vertex:
"""Vertex of the graph, everything except id and name is filled later"""
def __init__(self, id, name):
self.id = id
self.name = name
self.minDistance = float('inf')
self.previousVertex = None
self.edges = []
self.visited = False
class Dijkstra:
"""Dijkstra's algorithm implementation"""
def __init__(self):
self.vertexes = []
self.nodes = {}
self.unvisited = PriorityQueue()
def createGraph(self, vertexes, edgesToVertexes):
"""Connects edges to appropriate vertexes, adds vertexes to node dictionary"""
self.vertexes = vertexes
for vertex in self.vertexes:
for edge in edgesToVertexes:
if vertex.id == edge.source:
vertex.edges.append(edge)
edgesToVertexes.remove(edge)
self.nodes[vertex.id] = vertex
return 0
def getVertexes(self):
"""Returns vertexes in graph, should be called after creating it just to check"""
return self.vertexes
def computePath(self, sourceId):
"""Fills in minDistance and previousVertex of all nodes from source"""
mainNode = self.nodes[sourceId]
mainNode.minDistance = 0
self.unvisited.add(mainNode, 0)
while self.unvisited.head:
mainNode = self.unvisited.getMin()
mainNode.visited=True
for edge in mainNode.edges:
tempDistance = mainNode.minDistance + edge.weight
targetNode = self.nodes[edge.target]
self.unvisited.remove(mainNode)
if tempDistance < targetNode.minDistance:
targetNode.minDistance = tempDistance
targetNode.previousVertex = mainNode
self.unvisited.update(targetNode)
return 0
def getShortestPathTo(self, targetId):
"""Returns list of shortest parth to targetId from source. Call only after doing ComputePath"""
path = []
mainNode = self.nodes[targetId]
while True:
path.append(mainNode)
mainNode = mainNode.previousVertex
if not mainNode:
break
return list(reversed(path))
def resetDijkstra(self):
"""Resets ComputePath but leaves graph untouched"""
for vertex in self.vertexes:
vertex.minDistance = float('inf')
vertex.previousVertex = None
return 0
def createGraph(self, vertexes, edgesToVertexes):
"""Connects edges to appropriate vertexes, adds vertexes to node dictionary"""
self.vertexes = vertexes
for vertex in self.vertexes:
for edge in edgesToVertexes:
if vertex.id == edge.source:
vertex.edges.append(edge)
edgesToVertexes.remove(edge)
self.nodes[vertex.id] = vertex
return 0
I belive this was wrong => edgesToVertexes.remove(edge)
I had similar home work and used some of your code and this one line was incorrect I think. It removed one path from vortex in every loop.

Using a linked list in python to simulate standing in line

I have worked with linked lists and classes almost exclusively in c++, so I am having trouble getting this to work. The first class is supposed to have the variables name and next, an init function, two getter functions, and two setter functions. The second class(Line) is supposed to have an init function and an add function that adds items to the end of the linked list. I can't seem to get my add function to work. Any help is appreciated.
This is the code I have so far.
class PersonList():
"""
The class to represent the node in a linked list of people. It takes the variables:
name, which represents the person's name, and next_person, which links the next
person in the linked list.
"""
def __init__(self, name = None, next_ = None):
self.__name = name
self.__next = next_
def getName(self):
return self.__name
def getNext(self):
return self.__next
def setName(self, new_name):
self.__name = new_name
def setNext(self, new_person):
self.__next = new_person
def __str__(self):
return (self.__name)
def printlist(node):
next_node = node.getNext()
while next_node != None:
next_node = node.getNext()
print (node)
node = node.getNext()
class Line():
""" The class that represents the line of people as the linked list. Takes the variable
head, that denotes the first person in the line
"""
def __init__(self, head = None):
self.head = None
def add(self, name):
if self.head == None:
self.head = PersonList(name)
else:
Or just keep track of the tail to avoid traversing the whole list each time you want to add something:
class Line():
""" The class that represents the line of people as the linked list. Takes the variable
head, that denotes the first person in the line
"""
def __init__(self, head = None):
self.head = None
self.tail = None
def add(self, name):
tmp = PersonList(name)
if self.head == None:
self.head = tmp
self.tail = tmp
else:
self.tail.next = tmp
self.tail = tmp
def add(self, name):
if self.head == None:
self.head = PersonList(name)
else:
tmp = self.head
while tmp._next is not None: #while we are not at the end of the line
tmp = tmp._next
#end of line
tmp._next = PersonList(name) #get in line at the end
is one option

Categories

Resources