I am trying to write a simple method to link the nodes of a tree together in this way:
Every leaf is linked to the previous and the next leaf in the tree
Every non-leaf is linked to the previous and the next leaf in the tree
For example, if we have this tree:
A
/ | \
B C D
/ \ / \
E F G H
|
I
This should be the result of the method:
B.nextToken = E
C.prevToken = B
E.nextToken = F
E.prevToken = B
F.nextToken = I
C.nextToken = I
H.prevToken = I
Here is the method code:
prevToken = None
def depthFirstTraverseTokenLinking(tree):
global prevToken
if len(tree.children) == 0:
tree.prevToken = prevToken
if prevToken != None :
prevToken.nextToken = tree # Is something wrong with this line?
prevToken = tree
return
for c in tree.children:
depthFirstTraverseTokenLinking(c)
tree.prevToken = tree.children[0].prevToken
tree.nextToken = tree.children[-1].nextToken
For some strange reason, the non-leaves aren't linked to the next leaves, for example:
C.nextToken = None
Although
F.nextToken = I
I wonder why is that happening? The last lines at the end of the recursive function should grantee that a parent will have the same next as its last child!
The problem is, when you visit C, you traverse only it's children E & F.
"I" hasn't been visited yet, so C.children[-1].nextToken == None because only visiting "I" will set F.nextToken
Solution: you'll have to do a run on all leaves first, then a second run on the internal nodes.
For example:
prevToken = None
def depthFirstTraverseTokenLinking(tree):
depthFirstTraverseTokenLinkingPhase1(tree)
depthFirstTraverseTokenLinkingPhase2(tree)
def depthFirstTraverseTokenLinkingPhase1(tree):
global prevToken
if len(tree.children) == 0:
tree.prevToken = prevToken
if prevToken != None :
prevToken.nextToken = tree # Is something wrong with this line?
prevToken = tree
return
for c in tree.children:
depthFirstTraverseTokenLinkingPhase1(c)
def depthFirstTraverseTokenLinkingPhase2(tree):
if len(tree.children) == 0:
return
for c in tree.children:
depthFirstTraverseTokenLinkingPhase2(c)
if tree.children[0].prevToken is not None:
tree.prevToken = tree.children[0].prevToken
else:
tree.prevToken = tree.children[0]
if tree.children[-1].nextToken is not None:
tree.nextToken = tree.children[-1].nextToken
else:
tree.nextToken = tree.children[-1]
Also note the change for the prevToken/nextToken of internal nodes. This is needed if you want them to link to the actual first/last leaf.
Alternatively, use generators an an instance-checking loop
The generator yields the node as the base case if the node has no children, else another generator to travel down the tree. Caveat here is that node.children is ordered from left to right.
def leafs(node):
if len(node.children) == 0:
yield node
else:
for child in node.children:
yield leafs(child)
...and a loop with stack of generators... This got uglier as I wrote it - I think you could clean it up a bit and get rid of the while True...
current_node = leafs(a)
stack = []
last_node = None
while True:
if isinstance(current_node, types.GeneratorType):
stack.append(current_node)
current_node = current_node.next()
else:
if last_node and last_node != current_node:
last_node.nextToken = current_node
current_node.prevToken = last_node
last_node = current_node
try:
current_node = stack[-1].next()
except StopIteration:
stack.pop()
except IndexError:
break
Related
I am new to data structures and algorithms, and I got this question about merging 2 linked lists and making sure they are sorted. Since I am new, I don't really know much strategies and this is how I am trying to implement it. Can anyone point out what is going wrong and how I should tackle this question? Thanks in advance.
class Node:
def __init__(self, val):
self.val = val
self.next = None
def merge_lists(head_1, head_2):
tail_1 = head_1
tail_2 = head_2
tail_to_use = tail_2 if tail_1.val > tail_2.val else tail_1 # 5
current_h1 = head_1
current_h2 = head_2
while current_h1 is not None and current_h2 is not None:
if current_h1.val < current_h2.val and current_h1.val != tail_to_use.val:
tail_to_use.next = current_h2
current_h1 = current_h1.next
elif current_h2.val < current_h1.val and current_h2.val != tail_to_use.val:
tail_to_use.next = current_h2
current_h2 = current_h2.next
tail_to_use = tail_to_use.next
if current_h1 is not None:
tail_to_use.next = current_h1
if current_h2 is not None:
tail_to_use.next = current_h2
return head_1
This is one of the test cases I am trying to get to work
a = Node(5)
b = Node(7)
c = Node(10)
d = Node(12)
e = Node(20)
f = Node(28)
a.next = b
b.next = c
c.next = d
d.next = e
e.next = f
# 5 -> 7 -> 10 -> 12 -> 20 -> 28
q = Node(6)
r = Node(8)
s = Node(9)
t = Node(25)
q.next = r
r.next = s
s.next = t
# 6 -> 8 -> 9 -> 25
print(merge_lists(a, q))
There are several issues:
The loop may keep iterating infinitely if neither the if condition nor the elif condition is true. In that case current_h1 and current_h2 remain the same. This should never happen: in each iteration you should be sure to make some progress, and so there should be an else (not an elif) that catches all other cases.
Related: there should not be a reason to compare a value with tail_to_use.val. It should not be a condition. At first, I did not understand what your thinking was here, but then I realised you wanted to avoid to link back to the same node in the first iteration. There are two ways to do this right:
Either advance the relevant head reference to the next before the loop starts, so that tail_to_use is no longer a node whose value is compared inside the loop, or
Don't perform any logic before the loop, and start with tail_to_use as None, and deal with that state inside the loop.
The statement return head_1 will be wrong when head_2 has a value that is less than the value in head_1. In that case it should be return head_2. I would define a variable head that will take the right one (head_1 or head_2) and is returned at the end.
When doing print(merge_lists(a, q)) you must be sure to define how a list should be printed. You need to have some logic that defines the output. For that purpose you could define a __repr__ method on your class.
Not really a problem, but:
You can save some variables by using head_1 and head_2 to move along the lists, instead of using new current_* variables.
The to_use suffix in the name tail_to_use seems not to serve much. Just call it tail.
Here is a corrected version:
class Node:
def __init__(self, val):
self.val = val
self.next = None
def __repr__(self):
return str(self.val) + " -> " + str(self.next)
def merge_lists(head_1, head_2):
head = None
tail = None
while head_1 is not None and head_2 is not None:
if head_1.val < head_2.val:
next_node = head_1
head_1 = head_1.next
else:
next_node = head_2
head_2 = head_2.next
if head is None:
head = next_node
else:
tail.next = next_node
tail = next_node
if head_1 is not None:
tail.next = head_1
else:
tail.next = head_2
return head
My solution uses the merging method of Merge Sort.
Firstly it makes two list containing all the noded from the sequences. Than the lowest value node is selected and poped from the list. After that the algorithm goes though the lists and compares the first elements and adds the lower value node to the output sequence and removes it from the list, that is done until both of the lists are empty.
class Node:
def __init__(self, val):
self.val = val
self.next = None
def merge_lists(head_1, head_2):
list1 = [head_1]
i = head_1
while i is not None:
if i.next is not None:
list1.append(i.next)
i = i.next
list2 = [head_2]
i = head_2
while i is not None:
if i.next is not None:
list2.append(i.next)
i = i.next
print(list1, list2)
head = list1[0] if list1[0].val <= list2[0].val else list2[0]
list1.pop(0) if list1[0].val <= list2[0].val else list2.pop(0)
currentNode = head
while len(list1) or len(list2):
if not len(list1):
currentNode.next = list2[0]
currentNode = list2[0]
list2.pop(0)
elif not len(list2):
currentNode.next = list1[0]
currentNode = list1[0]
list1.pop(0)
elif list1[0].val <= list2[0].val:
currentNode.next = list1[0]
currentNode = list1[0]
list1.pop(0)
else:
currentNode.next = list2[0]
currentNode = list2[0]
list2.pop(0)
return head
I’m trying to implement a method that returns the index of a node at a particular index.
I can successfully retrieve the index when the element exists; however when it doesn’t I get an error 'NoneType' object has no attribute ‘data’ I can’t quite get why that happens.
here are my linked list and node classes
class Node:
def __init__(self,data = None,next = None):
self.data = data
self.next = next
class Listy:
def __init__(self):
self.head = None
and this is my get_index function
def get_index(self,key):
temp = self.head
count = 0
while temp.data != key:
temp = temp.next
count += 1
print(count)
Thank you for your help
You get an error because you are trying to get property 'data' of 'temp' in the while loop but your 'temp' is 'None' because you assigned it to 'self.head' which is actually 'None' in case of empty list. I hope this makes sense
The root caused is because the last node of LinkedList returns None,
let's change a bit Your Listy class code to avoid None value.
class Listy:
def __init__(self, nodes=None):
self.head = None
if nodes is not None:
node = Node(nodes.pop(0))
self.head = node
for elem in nodes:
node.next = Node(elem)
node = node.next
def get_index(self, key):
temp = self.head
count = 0
currentNode = temp.data
while temp is not None:
if count == key:
currentNode = temp.data
break
temp = temp.next
count += 1
return currentNode
Let's try to call:
if __name__ == "__main__":
nodes = ["a", "b", "c"]
ll = Listy(nodes)
idx_1 = ll.get_index(0)
idx_2 = ll.get_index(1)
print(idx_1)
print(idx_2)
Return will be as follow:
a
b
Your code is too optimistic about finding the key: it does not check whether you have reached the end of the list before finding the value, and so temp will become None resulting in an exception when temp.data is evaluated.
So change your loop to make sure that temp is still not None, and return the index when the key is found (instead of printing it):
def get_index(self, key):
temp = self.head
count = 0
while temp:
if temp.data == key:
return count
temp = temp.next
count += 1
Note how this will return None when the key is not found.
I am somehow new to python. I needed to use tree to store some data (file paths), The problem is when I generate the tree it seems that all objects after the root reference the same object, although step by step debugging showed the opposite. Here is my (minimized) code:
first the node class:
class PathElement:
Element = ""
IsStatic = True
Children = []
ChildrenCount = 0
def __init__(self, Element, IsStatic=True):
self.Element = Element
self.IsStatic = IsStatic
if not IsStatic:
self.Element = []
def AddChild(self, Child):
print(self, " ", Child)
self.Children.append(Child)
self.ChildrenCount = len(self.Children)
return Child
The Children is list of PathElement nodes. The code that build the tree:
def UnFoldAndCheck(self):
Path = PathElement("root")
Handler = Path
Index = 0
Count = len(self.Path)
while Index < Count:
element = self.Path[Index]
if something:
Child = None
Child = PathElement(element)
Handler.AddChild(Child)
Handler = None #Those added to debug the problem
Handler = Child
elif other_thing:
if condition:
if some_large_condition:
ChildExec = None
ChildExec = PathElement(element, False)
for i in range(0, 5):
ChildExec.Element.append(self.Path[Index + i])
Handler.AddChild(ChildExec)
Handler = None
Handler = ChildExec
Index += 4
elif another_condition:
ChildOp = None
ChildOp = PathElement(element, False)
Handler.AddChild(ChildOp)
Handler = None
Handler = ChildOp
elif some_else_condition:
if condition:
ChildExec = None
ChildExec = PathElement(element, False)
for i in range(0, 3):
ChildExec.Element.append(self.Path[Index + i])
Handler.AddChild(ChildExec)
Handler = None
Handler = ChildExec
Index += 2
elif different_condition:
ChildExec = None
ChildExec = PathElement(element, False)
for i in range(0, 3):
ChildExec.Element.append(self.Path[Index + i])
Handler.AddChild(ChildExec)
Handler = None
Handler = ChildExec
Index += 1
Index += 1
return Path
My problem is that after the tree is built when I use it it will have always same structure:
root -> object with 3 exact nodes -> same object -> same object to infinity
while the expected is:
root -> object -> first children -> second children -> third children -> etc
I'm sure the problem is related to how python handle object references but I can't see where the problem exactly. Any help?
Update:
I reproduced the problem with smaller code (same class PathElement):
from PathElement import PathElement
Path = PathElement("root")
Handler = Path
for i in range(1,6):
Child = PathElement("child"+str(i))
Handler.AddChild(Child)
Handler = Child
Tree = Path
while True:
print(Tree.Element)
if len(Tree.Children) > 0:
Tree = Tree.Children[0]
else:
break
This code will make infinite loop
I guess you come from Java or a similar language. It's important to stick with Python's conventions (Jakob Sachs gave you va link to the Style Guide for Python Code) because that makes your mistakes are easier to identify.
Now, what's wrong here? When you wrote:
class PathElement():
Children = []
Element = ""
IsStatic = True
ChildrenCount = 0
You don't give the initial value of instance fields. You create an initialize class (static) fields. Hence, Children is a static field of the class PathElement. Here's a illustration of that:
class A():
i = []
a = A()
b = A()
a.i.append(1)
b.i.append(2)
assert a.i == b.i == [1,2]
What happens when you try to make read the leftmost part of the tree (child 0, child 0 of child 0, ...)?
while True:
print(Tree.Element)
if len(Tree.Children) > 0:
Tree = Tree.Children[0]
else:
break
Just replace Tree.Children by what it is really: PathElement.Children, that is the static field Children of the class PathElement:
while True:
print(Tree.Element)
if len(PathElement.Children) > 0:
Tree = PathElement.Children[0] # Tree has always the same value.
else:
break
Now, a example of what you can write:
class PathElement:
def __init__(self, element):
self.__element = element
self.__children = []
def add_child(self, child):
self.__children.append(child)
def children(self):
return list(self.__children)
def element(self):
return self.__element
path = ["a", "b", "c", "d", "e", "f"]
root = PathElement("root")
handler = root
while path:
child = PathElement(path.pop(0)) # you can put some conditions here, take more elements of path, ...
handler.add_child(child)
handler = child
def dfs(node):
for c in node.children():
yield c.element()
yield from dfs(c)
print (list(dfs(root)))
# a b c d e f
I'm trying to implement a DFS algorithm to figure out if there is a path between a start node and a target node. Here's the code I have so far:
# Depth-first search
def find_path2(s, t):
s.visited = True
if s.data == t.data:
return True
for node in s.neighbors:
if not node.visited:
return find_path2(graph, node, t)
node_0 = Node(0)
node_1 = Node(1)
node_2 = Node(2)
node_3 = Node(3)
node_4 = Node(4)
node_5 = Node(5)
node_6 = Node(6)
node_0.neighbors = [node_1]
node_1.neighbors = [node_2]
node_2.neighbors = [node_3, node_0]
node_3.neighbors = [node_2]
node_4.neighbros = [node_6]
node_5.neighbros = [node_4]
node_6.neighbors = [node_5]
start = node_2
target = node_0
if find_path2(start, target):
print("There is a path between {} and {}".format(start.data, target.data))
else:
print("There is no path between {} and {}".format(start.data, target.data))
node_2 has both node_3 and node_0 as neighbors and so it should print that there is a path between them. I understand that the return statement is exiting the for loop during the first execution because a return statement exits the function and therefore never visits node_0.
My question is, what is the most elegant way to go about that? Thank you!
You need to make sure you only return from the loop over the neighbours if you've found the node you're looking for:
def find_path2(s, t):
s.visited = True
if s.data == t.data:
return True
for node in s.neighbors:
if not node.visited:
if find_path2(node, t):
return True
return False
This is just a very simple code and my reference is from here: http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Map/skip-list-impl.html#why-q
I think the insert function is okay but when I try to use the get() function, it doesn't return anything, instead it loops endlessly inside the searchEntry() part. I don't know what's wrong. In the insert() function, the searchEntry() operates well. It returns the reference to the floorEntry(k) entry containing a key that is smaller than the key that needs to be inserted in the skiplist. Please help me figure out the source of the error in the searchEntry() function. I'm sorry I'm not really good at this. Thank you!
from QuadLinkedList import QLLNode
import random
class Skippy:
def __init__(self):
self._p1 = QLLNode("MINUS_INF")
self._p2 = QLLNode("PLUS_INF")
self._head = self._p1
self._tail = self._p2
self._p1.setNext(self._p2)
self._p2.setPrev(self._p1)
self._height = 0
self._n = 0
def insert(self, key, value):
p = self.searchEntry(key)
print "p = " + str(p.getKey())
q = QLLNode(key, value)
q.setPrev(p)
q.setNext(p.getNext())
p.getNext().setPrev(q)
p.setNext(q)
i = 0
while random.randint(0,1) != 0:
if i >= self._height:
self._height += 1
newHead = QLLNode("MINUS_INF")
newTail = QLLNode("PLUS_INF")
newHead.setNext(newTail)
newHead.setDown(self._head)
newTail.setPrev(newHead)
newTail.setDown(self._tail)
self._head.setUp(newHead)
self._tail.setUp(newTail)
self._head = newHead
self._tail = newTail
while p.getUp() == None:
p = p.getPrev()
p = p.getUp()
e = QLLNode(key,None)
e.setPrev(p)
e.setNext(p.getNext())
e.setDown(q)
p.getNext().setPrev(e)
p.setNext(e)
q.setUp(e)
q = e
i += 1
self._n += 1
return None
def get(self, key):
p = self.searchEntry(key)
if key == p.getKey():
return p.getElement()
else:
return "There's None!"
def searchEntry(self, key):
p = self._head
while True:
while p.getNext().getKey() != "PLUS_INF" and p.getNext().getKey() <= key:
p = p.getNext()
if p.getDown() != None:
p = p.getDown()
else:
break
return p
The issue isn't in the code for searchEntry, which appears to have the correct logic. The problem is that the list structure is getting messed up. I believe the issue is with the code you have for adding a new level to the list in insert. Specifically this bit:
if i >= self._height: #make an empty level
self._height += 1
self._minus.setNext(self._plus)
self._minus.setDown(self._head)
self._plus.setPrev(self._minus)
self._plus.setDown(self._tail)
self._head.setUp(self._minus)
self._tail.setUp(self._plus)
self._head = self._minus
self._tail = self._plus
The thing that stands out to me about this code is that you're not creating any new nodes, just modifying existing ones, which is what is breaking your list structure. You need to create new head and tail nodes, I think, and link them into the top of the strucutre. (minus and plus are not part of the algorithm as described at your link, so I'm not sure what you're doing with them.) Probably you want something like this:
if i >= self._height: #make an empty level
self._height += 1
newHead = QLLNode("MINUS_INF")
newTail = QLLNode("PLUS_INF")
newHead.setNext(newTail)
newHead.setDown(self._head)
newTail.setPrev(newHead)
newTail.setDown(self._tail)
self._head.setUp(newHead)
self._head = newHead
self._tail.setUp(newTail)
self._tail = newTail