Inserting into n-child tree in Python - python

I am trying to implement a tree for the travelling salesperson problem. My particular tree has 5 destinations which are fully connected to each other.
One of the destinations is guaranteed to always be the starting destination and that you are only allowed to visit each destination once with the exception of the starting destination which you have to return to (ie if you have [1,2,3,4,5] with 1 the starting destination, a possible sequence of moves would be 1-3-5-2-4-1)
I tried implementing a tree in python with the following code (I brute forced it since I know the maximum depth is going to be 5).
class Node(object):
def __init__(self,value, city, children = [None, None, None, None]):
self.value = value
self.city = city
self.children = children
class Tree(object):
def __init__(self):
self.root = None
def insert(self,value,city):
newNode = Node(value,city)
if self.root is None:
self.root = newNode
else:
self._insert(1, newNode)
def _insert(self,depth, newNode):
if depth is 1:
for x in range(0,4):
if self.root.children[x] is None:
self.root.children[x] = newNode
return
elif self.root.children[3] is not None:
self._insert(2, newNode)
return
if depth is 2:
for x in range(0,4):
for y in range(0,3):
if self.root.children[x].children[y] is None:
self.root.children[x].children[y] = newNode
return
elif self.root.children[3].children[2] is not None:
self._insert(3, newNode)
return
if depth is 3:
for w in range(0,4):
for x in range(0,3):
for y in range(0,2):
if self.root.children[w].children[x].children[y] is None:
self.root.children[w].children[x].children[y] = newNode
return
elif self.root.children[3].children[2].children[1] is not None:
self._insert(4,newNode)
return
if depth is 4:
for w in range(0,4):
for x in range(0,3):
for y in range(0,2):
for z in range(0,1):
if self.root.children[w].children[x].children[y].children[z] is None:
self.root.children[w].children[x].children[y].children[z] = newNode
return
elif self.root.children[3].children[2].children[1].children[0] is not None:
self._insert(5,newNode)
return
if depth is 5:
for w in range(0,4):
for x in range(0,3):
for y in range(0,2):
for z in range(0,1):
for u in range(0,1):
if self.root.children[w].children[x].children[y].children[z].children[u] is None:
self.root.children[w].children[x].children[y].children[z].children[u] = newNode
return
elif self.root.children[3].children[2].children[1].children[0].children[0] is not None and w is 3 and x is 2 and y is 1 and z is 0 and u is 0:
print "The table is full"
def delete(self):
self.root = None
x = Tree()
x.insert(0, "Pretoria")
x.insert(60, "Johannesburg")
x.insert(1200, "Cape Town")
x.insert (600, "Durban")
x.insert(400, "Bloemfontein")
x.insert(1400, "Port Elizabeth")
My root and first level populate correctly but all the children nodes of the second, third, fourth and fifth level all populate exactly the same as the first level. When I checked their memory, they all populated the exact same memory space and I have no idea why. This happens when the following line of code runs:
x.insert(1400, "Port Elizabeth")
The tree for some reason is fully populated at this point despite only having 5 entries.
I tried using pointers at first but the same issue crops up.
Long story short, how would one go about inserting into an n-ary tree with decreasing n as you increase in depth?
This particular tree has the following attributes:
Root: 4 children per node (1 node with 4 children)
Level 1: 3 children per node (4 nodes with 3 children)
Level 2: 2 children per node (12 nodes with 2 children)
level 3: 1 child per node (24 nodes with 1 child)
level 4: 1 child per node (24 nodes with 1 child) (this is final destination in the TSP)

Related

A* Search for Maze - Infinite Loop When Path does not Exist - Python

I am trying to implement an A-star search algorithm to find a path in a square maze from (0,0) to (dimension - 1, dimension - 1). My algorithm returns the correct path when it exists; however, if there is no path, then it runs in an infinite loop. How do I fix this? For now, I've put a condition to run if the length of the open list exceeds (dimension ^ 4), but this is obviously not a permanent fix. I am using Python 3.7.3.
import numpy as np
class node():
def __init__(self, parent=None, location=None):
self.parent = parent
self.location = location
self.g = float(0)
self.h = float(0)
self.f = float(0)
#returns euclidean distance between two nodes
#takes the locations/tuples of two nodes as arguments
#works properly
def euclidean_distance(node_1, node_2):
return float((((node_2[1] - node_1[1])**2) + ((node_2[0] - node_1[0])**2))**0.5)
#to make extracting the value at a given location in the maze easier
#takes the maze and two integers as arguments
def get_value(maze, a, b):
return maze[a][b]
def out_of_bounds(a, b, dim):
return (a < 0 or a >= dim) or (b < 0 or b >= dim)
#Euclidean A* Search, takes the maze and dimension as arguments
def a_star_euclidean(maze, dim):
#initializing start node and end node
start = node(None, (0,0))
end = node(None, (dim-1, dim-1))
#initializing open list and closed list
open_list = []
closed_list = []
open_list.append(start)
while len(open_list) > 0:
#assigning currentNode
currentNode = open_list[0]
currentNode_index = 0
#current location
for index, item in enumerate(open_list):
if item.f < currentNode.f:
currentNode = item
currentNode_index = index
#(currentNode.location)
row = currentNode.location[0]
column = currentNode.location[1]
#updating open list and closed list
open_list.pop(currentNode_index)
closed_list.append(currentNode)
#in case goal node is already reached
if currentNode.location == end.location:
path = []
current = currentNode
while current is not None:
path.append(current.location)
current = current.parent
#return path[::-1] #returning the path from start to end
path.reverse()
return path
else:
closed_list.append(currentNode)
#generating childs
child_locations = [(row+1, column), (row-1, column), (row, column+1), (row, column-1)]
#print(child_locations)
child_nodes = [node(currentNode, location) for location in child_locations]
#print(child_nodes)
for child in child_nodes:
#declaring row and column variables for child nodes
child_row = int(child.location[0])
child_column = int(child.location[1])
if not out_of_bounds(child_row, child_column, dim):
# Child is on the closed list
if child in open_list:
continue
#computing g(n), h(n), f(n)
child.g = float(currentNode.g + 1)
child.h = float(euclidean_distance(child.location, end.location))
child.f = float(child.g + child.h)
#child is in open list
if child in closed_list:
continue
if get_value(maze, child_row, child_column) == 0:
open_list.append(child)
else:
continue
else:
continue
#if (len(open_list) > dim**4): #b^d worst case
#return None
def main():
maze = []
dim = int(input("Enter the dimension of the game: "))
print(dim)
for row in range(dim):
maze.append([])
for column in range(dim):
maze[row].append(int(np.random.binomial(1, 0.3, 1)))
maze[0][0] = 0
maze[dim-1][dim-1] = 0
print(maze)
print("----------")
print(a_star_euclidean(maze,dim))
#print(euclidean_distance((1,1), (2,2)))
main()
I believe the issue is that child in closed_list is never true, because you haven't overriden the __eq__ operator of the node class. Because of this, python doesn't know how to compare two instances of the node class, so falls back to comparing if they are references to the same object in memory, otherwise it returns false. So two nodes are never equal when searching through closed_list.
Try defining the __eq__ operator for the node class like so. You can change the comparison to include other properties as you need.
class node():
def __init__(self, parent=None, location=None):
self.parent = parent
self.location = location
self.g = float(0)
self.h = float(0)
self.f = float(0)
def __eq__(self, other):
return self.location == other.location

Building a Binary Search Tree from a file

I have a text file of lines in the format
2 0 0
7 0 0
4 1 1
10 0 0
9 0 1
8 1 1
These lines represent the data in a binary search tree where the first element is the node data, the second is whether or not a left child exists ( 0 if no, 1 if yes) and the third is whether or not a right child exists (0 if no, 1 if yes)
I have a class called "BinarySearchTree" which has the following initialization function
def __init__(self, value=None):
# Initializes the tree with a value node, a left child and a right child
self.leftChild = None
self.rightChild = None
self.height = 1
self.value = value
I also have a stack class with the following "push" and "pop" functions:
def push(self, item):
# Adds an item to the beginning of the stack
ending = self.stack
self.stack = [item] + [ending]
def pop(self):
# Removes and returns the first element from the stack
if self.isEmpty():
return None
top_element = self.stack[0]
self.stack = self.stack[1:]
return top_element
I am trying to create a binary search tree instance from the lines in the text file and using the stack class. So far I have:
def loadTreeFromFile(filename):
binarySearchTree = stack.Stack()
with open(filename) as file:
# gets a list containing only the elements in the txt file
for level in file.readlines():
nodeInfo = level.rstrip().split()
data, lc, rc = int(nodeInfo[0]), int(nodeInfo[1]), int(nodeInfo[2])
print(data, lc, rc)
if rc == 1:
right_tree = binarySearchTree.pop()
if lc == 1:
left_tree = binarySearchTree.pop()
newTree = BinarySearchTree(data)
if rc == 1:
newTree.rightChild = right_tree
if lc == 1:
newTree.leftChild = left_tree
binarySearchTree.push(newTree)
return newTree
I am running into the problem when I try to display the BST, I get 8: [[[<__main__.BinarySearchTree object at 0x1033e4390>, []]], 9: [None, 10: [None, None]]] (I have a display function written for the BST class so this is not the problem) AND when I try to do anything with this newly created BST (such as get the depth, search it, etc), I get errors. Any help is much appreciated, thanks .

Successor and Predecessor - Binary Search Tree (Python)

I am trying out this successor and predecessor on Binary search tree.
Just wondering once I get hold of successor code, can I flip it over and use it for predecessor?
I've coded the successor, and tried to use it for predecessor.
However, my output value doesn't change, even though I tried to place other value..
Below is my code:
Succ
def succ(self, key):
temp = self.root
prev = None
if (temp.right is not None):
temp = temp.right
while (temp.left is not None):
temp = temp.left
prev = temp
elif temp.left is not None:e
temp = temp.left
while (temp.right is not None):
temp = temp.right
prev = temp
else:
return None
return prev.key
Predecessor
def pred(self, key):
temp = self.root
prev = None
#if right is not none, succ lies in the right sub tree
if (temp.right is not None):
temp = temp.right
while (temp.left is not None):
#return the node with the minimum key value
temp = temp.left
prev = temp
#if left not none, succ lies in the right sub tree
elif temp.left is not None:
#go right till .right is None
#return the node with the maximum key value
temp = temp.left
while (temp.right is not None):
temp = temp.right
prev = temp
else:
#no succ
return None
return prev.key
the tree
def createTree(self):
#root
self.put("F",6)
#leftSubTree
self.put("D",4)
#leftLeftSubTree
self.put("C",3)
self.put("B",2)
self.put("A",1)
#LeftRightSubTree
self.put("E",5)
#RightSubTree
self.put("I",9)
#RightLeftSubTree
self.put("G",7)
self.put("H",8)
#RightRightSubTree
self.put("J",10)
To flip the succ function and turn it into pred, you need to change every left to a right, and every right to a left.
def pred(self, key):
temp = self.root
prev = None
if (temp.left is not None):
temp = temp.left
while (temp.right is not None):
temp = temp.right
prev = temp
elif temp.right is not None:
temp = temp.right
while (temp.left is not None):
temp = temp.left
prev = temp
else:
return None
return prev.key
Let us assume you have a BST node class with three pointers/references: left, right, and parent, which correspond to the left child, right child, and parent of a given node. The only node in the tree which has a parent that points to None would be the root node.
Let us also assume that we have the following BST:
15
/ \
9 20
/ \ / \
3 10 17 21
/ \ \
1 5 11
The BST property states that for any given node n, all nodes in n's left sub-tree shall be less than n; and, all nodes in n's right sub-tree shall be greater than n.
To make things easier when implementing the successor and predecessor functions, it is helpful to have auxiliary functions for finding the minimum and maximum node of a given BST or BST sub-tree.
Minimum
def bst_minimum(tree):
minimum = tree
while minimum is not None:
minimum = minimum.left
return minimum
Maximum
def bst_maximum(tree):
maximum = tree
while maximum is not None:
maximum = maximum.right
return maximum
For the tree example above, these functions would return 1 for the minimum and 21 for the maximum.
To find the predecessor of a given node, you have to cover a few cases:
If the given node has a left sub-tree, then take the maximum of that sub-tree.
Otherwise, move up the tree, following parent nodes until either you hit None or you "turn left."
In the second case, if you hit None, that means there is no predecessor. This would be the case for the node with value 1 in the tree above. It would following parent pointers all the way past the root node.
If there is a predecessor, then it will be the first parent node you encounter after making a left turn up the tree. Put another way, it is the parent node whose value is less than the value of the node from which you started. So, node 17 above would return the root node with a value of 15.
Predecessor
def bst_predecessor(tree):
if tree.left is not None:
return bst_maximum(tree.left)
parent = tree.parent
child = tree
while parent is not None and child is parent.left:
child = parent
parent = child.parent
return parent
Since the successor is simply the symmetrical operation to predecessor, you can modify predecessor by flipping the various operations. Namely:
Instead of checking the left sub-tree and finding the maximum, you want to check the right tree and find its minimum.
Otherwise, follow parent nodes until you can't anymore (in which case there is no successor), or you turn right. So, the successor of node 5, would be node 9 in the tree above.
Successor
def bst_successor(tree):
if tree.right is not None:
return bst_minimum(tree.right)
parent = tree.parent
child = tree
while parent is not None and child is parent.right:
child = parent
parent = child.parent
return parent

Recursive insert into a tree with 4 children

I'm trying to construct a tree in Python that can take 4 children. The children are defined as an array.
What I'm struggling with is inserting recursively into this tree.
Here is what I've done so far:
Node Class:
class node:
def __init__(self,value,city,children=[None,None,None,None]):
self.value = value
self.children = children
self.city = city
Tree Class:
from node import *
from isFull import *
class tree:
root = None
def __int__(self):
self.root = None
def insert(self, city, value):
if self.root == None:
self.root = node(value, city, children=[None,None,None,None])
else:
self.rec_insert(city, value, self.root, 0)
def rec_insert(self, city, value, nodes, index):
if nodes.children[index] is None:
nodes.children[index] = node(value, city, children=[None,None,None,None])
return
elif index < 3:
self.rec_insert(city, value, nodes, index + 1)
elif index == 3:
self.rec_insert(city, value, nodes.children[0], 0)
So what I have observed is that this first if statement actually works. I can insert a root and into the first layer of children.
if nodes.children[index] is None:
Now the problem arises in level 2. Probably because I'm descending wrong.
At the start I can insert normally into layer 2, however as it gets to the right side of the tree it skips the last child in layer 2.
My logic behind this function:
self.rec_insert(city, value, nodes.children[0], 0)
I wanted to make it descend just into the left most child then my other conditional statements will make it shift right as it inserts.
This check:
elif index == 3:
I use it to determine if all the children have been inserted into in a node.
Any help will be appreciated.

Implementing Binary Search Tree (Python)

I have the task to perform some basic operations on Binary Search Trees and I'm not sure what is the clever way to do it.
I know that the usual way would be to write a class for the nodes and one for the tree so that I can build up my tree from given values and perform certain tasks on it. The thing is, I'm already getting the tree as a list and since BSTs are not unique, there won't come any good from it if I take each value and build the tree myself.
So... I'm getting a list like this:
11 9 2 13 _, 4 18 2 14 _, 2 10 _ 11 4, 14 16 4 _ _, 13 0 11 _ _ | 10 | 7
which means:
key value parent left right, ... | value1 | value2
So as you see the BST is given explicitly. My tasks are to do a level-print of the tree, return the path from root to value1, do a rotate-right operation on the subtree that has value1, then delete value1 and then insert value2.
What would be an efficient way to tackle this problem?
Here is one possible way of implementing the tree. Hope it helps. Though this contains insertions and popular traversals, not rotations or deletions.
Reference: http://www.thelearningpoint.net/computer-science/learning-python-programming-and-data-structures/learning-python-programming-and-data-structures--tutorial-20--graphs-breadth-and-depth-first-search-bfsdfs-dijkstra-algorithm-topological-search
'''
Binary Search Tree is a binary tree(that is every node has two branches),
in which the values contained in the left subtree is always less than the
root of that subtree, and the values contained in the right subtree is
always greater than the value of the root of the right subtree.
For more information about binary search trees, refer to :
http://en.wikipedia.org/wiki/Binary_search_tree
'''
#Only for use in Python 2.6.0a2 and later
from __future__ import print_function
class Node:
# Constructor to initialize data
# If data is not given by user,its taken as None
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
# __str__ returns string equivalent of Object
def __str__(self):
return "Node[Data = %s]" % (self.data,)
class BinarySearchTree:
def __init__(self):
self.root = None
'''
While inserting values in a binary search tree, we first check
whether the value is greater than, lesser than or equal to the
root of the tree.
We initialize current node as the root.
If the value is greater than the current node value, then we know that
its right location will be in the right subtree. So we make the current
element as the right node.
If the value is lesser than the current node value, then we know that
its right location will be in the left subtree. So we make the current
element as the left node.
If the value is equal to the current node value, then we know that the
value is already contained in the tree and doesn't need to be reinserted.
So we break from the loop.
'''
def insert(self, val):
if (self.root == None):
self.root = Node(val)
else:
current = self.root
while 1:
if (current.data > val):
if (current.left == None):
current.left = Node(val)
break
else:
current = current.left
elif (current.data < val):
if (current.right == None):
current.right = Node(val)
break
else:
current = current.right
else:
break
'''
In preorder traversal, we first print the current element, then
move on to the left subtree and finally to the right subree.
'''
def preorder(self, node):
if (node == None):
return
else:
print(node.data, end=" ")
self.preorder(node.left)
self.preorder(node.right)
'''
In inorder traversal, we first move to the left subtree, then print
the current element and finally move to the right subtree.
'''
#Important : Inorder traversal returns the elements in sorted form.
def inorder(self, node):
if (node == None):
return
else:
self.inorder(node.left)
print(node.data, end=" ")
self.inorder(node.right)
'''
In postorder traversal, we first move to the left subtree, then to the
right subtree and finally print the current element.
'''
def postorder(self, node):
if (node == None):
return
else:
self.postorder(node.left)
self.postorder(node.right)
print(node.data, end=" ")
tree = BinarySearchTree()
tree.insert(1)
tree.insert(9)
tree.insert(4)
tree.insert(3)
tree.insert(5)
tree.insert(7)
tree.insert(10)
tree.insert(0)
print ("Preorder Printing")
tree.preorder(tree.root)
print("\n\nInorder Printing")
tree.inorder(tree.root)
print("\n\nPostOrder Printing")
tree.postorder(tree.root)
Here is the implementation of Binary Search Tree with it's basic operations like insert node, find node
class Node:
def __init__(self,data):
self.left = None
self.right = None
self.data = data
class BST:
def __init__(self):
self.root = None
def set_root(self,data):
self.root = Node(data)
def insert_node(self,data):
if self.root is None:
self.set_root(data)
else:
n = Node(data)
troot = self.root
while troot:
if data < troot.data:
if troot.left:
troot = troot.left
else:
troot.left = n
break
else:
if troot.right:
troot = troot.right
else:
troot.right = n
break
def search_node(self,data):
if self.root is None:
return "Not found"
else:
troot = self.root
while troot:
if data < troot.data:
if troot.left:
troot = troot.left
if troot.data == data:
return "Found"
else:
return "Not found"
elif data > troot.data:
if troot.right:
troot = troot.right
if troot.data == data:
return "Found"
else:
return "Not found"
else:
return "Found"
tree = BST()
tree.insert_node(10)
tree.insert_node(5)
tree.insert_node(20)
tree.insert_node(7)
print(tree.root.data)
print(tree.root.left.data)
print(tree.root.right.data)
print(tree.root.left.right.data)
print(tree.search_node(10))
print(tree.search_node(5))
print(tree.search_node(20))
print(tree.search_node(7))
print(tree.search_node(12))
print(tree.search_node(15))
Output:
10
5
20
7
Found
Found
Found
Found
Not found
Not found
In this specific case I had success using a dictionary as a datatype to store the graph. The key is the node_key and the value is a list with the attributes of the node. In this way it is rather fast to find the needed nodes and all its attributes.
I'm just not sure if there is a way to make it reasonably faster.

Categories