Breadth First Search Python code to Depth First Search - python

I have written some code that conducts a BFS when a graph is defined. I now need to Edit the code to do a DFS, does anyone know what i need to change to complete this?
This is the BFS code i have now:
class MyQUEUE: # Just an implementation of a queue.
def __init__(self): # Initialises the queue to an empty queue.
self.holder = []
def enqueue(self,val):
# Appends item val onto the end of the queue.
self.holder.append(val)
def dequeue(self):
# Pops the head off the queue and returns it value.
val = None
try:
val = self.holder[0]
if len(self.holder) == 1:
self.holder = []
else:
self.holder = self.holder[1:]
except:
pass
return val
def IsEmpty(self):
# Returns True if the queue is empty.
result = False
if len(self.holder) == 0:
result = True
return result
def BFS(graph,start,end):
# Traverses the graph using a Breadth First Search starting
# from the start node with end being the goal node. Uses a
# queue to store the nodes that are current leaves at the
# fringe of the search.
q = MyQUEUE() # make an empty queue first
q.enqueue([start]) # add the start node onto the queue
while q.IsEmpty() == False:
path = q.dequeue()
last_node = path[len(path)-1]
print (path)
if last_node == end:
print ("VALID_PATH : ", path)
for link_node in graph[last_node]:
if link_node not in path:
new_path = []
new_path = path + [link_node]
q.enqueue(new_path)

Instead of append - insert at the beginning:
modify:
self.holder.append(val)
to:
self.holder.insert(0, val)
Explanation
While BFS "pills" the neighbors "layer by layer" a DFS goes "all the way to the bottom" and back. By changing the order we iterate the neighbors (recursively) we are, in fact, modifying the BFS into DFS.
UPDATE
As Kaya commented below, if we care about performance we should use append/pop instead of insert because insert takes O(n) while append/pop are O(1)

Related

Putting Stack in descending order using push and pop in python

accepts strings from user and generates stack till it gets the input "End"
Next, it should sort the given stack in a decent order
Finally, print the sorted stack
I cannot seem to get the logic right using only push and pop methods whereby push is a function putting elements to the top of the stack and pop is a function removing the top element of the stack and storing it. I am only allowed to use push and pop, the sorting algorithm is the only one I cant do.
from Stack import Stack
def display_(S_):
node = S_.list.head
while node != None:
print(node.data)
node = node.next
def Sorting_Stack(stack,k):
v = 0
ar = 0
temp = Stack()
for i in range(k):
v = stack.pop()
temp.push(v)
node = stack.list.head
tnode = temp.list.head
if tnode.data > node.data:
ar = temp.pop()
stack.push(ar)
display_(stack)
if __name__ == '__main__':
stack = Stack()
string = ""
k = 0
while string!='End':
string = input()
if string == 'End':
break
else:
stack.push(string)
k += 1
Sorting_Stack(stack, k)
#this is Stack.py--------
from Node import Node
from LinkedList import LinkedList
class Stack:
def __init__(self):
self.list = LinkedList()
def push(self, new_item):
# Create a new node to hold the item
new_node = Node(new_item)
# Insert the node as the list head (top of stack)
self.list.prepend(new_node)
def pop(self):
# Copy data from list's head node (stack's top node)
popped_item = self.list.head.data
# Remove list head
self.list.remove_after(None)
# Return the popped item
return popped_item
#Stack Class
class Stack:
def __init__(self):
self.stack = []
def push(self,item):
if item == 'End':
self.sort()
else:
self.stack.append(item)
def pop(self):
if len(self.stack) == 0:
print("Stack Is Empty")
else:
self.stack.pop()
def sort(self):
self.stack.sort()
print(self.stack)
logic For giving Inputs
s = Stack()
item = None
while item !='End':
print("Type 'End' For Ending the Stack Push Operation")
item = input("Enter Item: ")
s.push(item)
s.push(item)
Program will take inputs till we give input as 'End'.
After given 'End' as Input it will sort the stack and print it.

Can I be helped in knowing my mistake in the insertion and searching operations of a BST?

I am implementing a BST in Python. I have written the functions for inserting data and searching for it in a BST.
The problem is, I have tried many times to find out what mistake I am making, but I haven't been able to do it correct.
I request for some help. Please help me.
class Node:
def __init__(self, data):
self.data = data
self.left_ptr = None
self.right_ptr = None
class BinarySearchTree:
def __init__(self):
self.ptr_to_root = None
def insert(self, data):
'''
This feature/function helps the users to insert data into a Binary
Search Tree.
'''
# To insert, the first thing we have to do is
# creating a node :-
node = Node(data)
# We create a temperory pointer as we
# won't move ptr_to_root.
temp_ptr = self.ptr_to_root
# CASE 1 > If ptr_to_root is None i.e. If BST
# is empty :
if temp_ptr == None:
temp_ptr = node
# CASE 2 > If BST is not empty already :
while temp_ptr != None:
# Below is the pointer which will remain behind
# temp_ptr by one step.
r = temp_ptr
# If we already have the data present in BST, we
# cannot re-enter it. Hence, we simply exit the
# function.
if data == temp_ptr.data:
return
# If the data is having lesser value then temp_ptr's data,
# then we move the temp_ptr to its left, or else the right.
if data < temp_ptr.data:
temp_ptr = temp_ptr.left_ptr
else:
temp_ptr = temp_ptr.right_ptr
# r is the tail pointer, which follows the temp_ptr.
# Eventually, we will compare if the value that we wanrt to insert
# is less or more then r.data, and accordingly insert the data desired.
if data < r.data:
r.left_ptr = node
else:
r.right_ptr = node
def search(self, data):
# If the BST is empty, then we do not
# have the element present in the BST for sure:
temp_ptr = self.ptr_to_root
# If BST is empty, then :
if temp_ptr == None:
return None
# If BST is not empty, we may or may not be
# finding the element in the tree :
while temp_ptr != None:
if data == temp_ptr.data:
return temp_ptr
elif data < temp_ptr.data:
temp_ptr = temp_ptr.left_ptr
else:
temp_ptr = temp_ptr.right_ptr
# If the element is not present in BST :
return None
When I run the above code for inserting an element and then searching for it; It returns 'None' even though I search for an element that I have inserted.
Please Help!
Your problem is actually very simple, as a few minutes with a debugger would have shown you. You never create a root node. When you try to insert something into an empty tree, you set up the node, but you don't save it, so the tree is ALWAYS empty. Change this:
# CASE 1 > If ptr_to_root is None i.e. If BST
# is empty :
if temp_ptr == None:
temp_ptr = node
self.ptr_to_root = node # <<< add this line
and it all works.

Sorting a linked list (swapping nodes)

I am trying to sort a LinkedList containing of such nodes:
class Node:
def __init__(self, data, next=None):
self.data, self.next = data, next
The idea is to get a sequence (list/tuple/string) from which a LinkedList is created:
def __init__(self, seq):
self.front = self.Node(None)
node = self.front
for item in seq:
node.next = self.Node(item)
node = node.next
The logic of the sort is that in each iteration you go through the linkedlist, compare each item with the first, if its smaller/greater then you perform a swap, continue going through the linked list and do the same comparation and operation. Shown here:
def min_sort(self, reverse):
self.count = 0
first = self.front
while first.next is not None:
print(self.get_list())
self.progress(first, reverse)
self.count += 1
first = first.next
def progress(self, first, reverse):
node = first
if (node is None): return
while True:
node = node.next
if node is None or node.next is None: break
if (reverse):
if (first.next.data < node.next.data):
self.vymen(first, node, node.next)
else:
if (first.next.data > node.next.data):
self.vymen(first, node, node.next)
The issue is with the swap itself (function self.vymen(...)), where with basic LinkedList of numbers it usually works, however when loaded with a string e.g. "I code in Python", the spaces dont get swapped to the correct position making the whole result messed up.
The swap itself is:
def vymen(self, first, prev, swap):
prevX, currX, prevY, currY = first, first.next, prev, swap
if (self.front.next.data == swap.data): return
if (currX is None or currY is None): return
if (currX != prevY):
if (prevX is not None): prevX.next = currY
else: self.front = currY
if (prevY is not None): prevY.next = currX
else: self.front = currX
temp = currX.next
currX.next = currY.next
currY.next = temp
else:
temp = currY.next
currX.next = temp
currY.next = currX
prevX.next = currY
Its really just an issue with the spaces as I can see and I dont understand whats the issue, since it swaps the first space on the beginning but not the rest. I would be thankful if someone would be able to point out a mistake or give me an idea whats happening :)
There are two issues in your code:
The following statement in vymen is the cause of trouble:
if (self.front.next.data == swap.data): return
Its intention is to avoid an unnecessary swap when the data of the swapped nodes are equal. But then it should not reference self.front.next, but curX -- as that is the node that is to be swapped:
if currX.data == currY.data:
return
The if condition that follows after it, is not useful at this point:
if (currX is None or currY is None): return
...as we already referenced swap.data (i.e. currY.data) at this point. So if this really were possible, it should be checked before referencing currY.data or currX.data. So combine it with the previous if:
if currX is None or currY is None or currX.data == currY.data:
return
The main loop in progress will skip a node when two consecutive(!) nodes are swapped. In that case, before the call to vymen, node will become currX that will hop over node.next. And so after the call, node will still reference the same node, but its position in the list is one further. By consequence, there is a node that will not haven an iteration of the loop. This is a cause of getting wrong outputs, even with plain numbers. To solve this, you could adapt vymen so it will return the node that will be at the same position as node was at the start of the call. The caller should then re-assign that reference to its node variable.
Some other remarks:
In Python it is not needed to put parentheses around if conditions
In vymen, the following condition should always be true:
if (prevX is not None): prevX.next = currY
else: self.front = currY
This should never be true, because you have designed your linked list to have a sentinel node at its front (having value None). So you don't even want self.front = currY to ever execute! prevX should never be None. It never is None in the way you call this function either. So just remove this construct and just assign:
prevX.next = currY
The same should happen with the if..else that follows it.
The vymen shoudn't need its last argument (swap), as it should always be the value of prev.next. So the function could start like this:
def vymen(self, first, prev):
prevX, currX, prevY, currY = first, first.next, prev, prev.next
And the call would be (note also the assignment of the return value):
node = self.vymen(first, node)
It is a pity that right after the function header of vymen, you define new variables for exactly the same as first and prev: prevX and prevY. Why not name the parameter variables like that immediately?
It is a pity that in progress you have an if with a break as the first statement in the while True body. You can better rewrite this so to have the condition in the while statement
Taking it all together, this is the resulting code for the two methods that had problems:
def progress(self, first, reverse):
if first is None or first.next is None:
return
node = first.next
while node.next: # Use a condition to exit instead of break
if reverse:
if first.next.data < node.next.data:
# Take the return value, and pass one argument less
node = self.vymen(first, node)
else:
if first.next.data > node.next.data:
# Take the return value, and pass one argument less
node = self.vymen(first, node)
node = node.next
def vymen(self, prevX, prevY): # Use the desired variable names
# No need for the swap argument
currX, currY = prevX.next, prevY.next
# Corrected comparison of the two nodes' data, and put the
# conditions in the right order:
if currX is None or currY is None or currX.data == currY.data:
return prev # return the node at the position of prev
if currX != prevY:
# Make the following assignments unconditionally
prevX.next = currY
prevY.next = currX
temp = currX.next
currX.next = currY.next
currY.next = temp
# Return the reference of the node that is in the position
# of prev: it is still in the same position:
return prev
else:
temp = currY.next
currX.next = temp
currY.next = currX
prevX.next = currY
# Return the reference of the node that is in the position
# of prev: it has moved, so now it is...:
return currY

How to find the minimum, and maximum value within a Binary Tree

++ EDIT ++
Thanks to all of you, I have taken many compartments to get the code to finally working.
Here's the full code overview
class Node:
# Binary Roots: Left and Right, initiating data
def __init__(self, data):
# Creating an object, Data, to be used for inputs
self.data = data
# The objects are defined as None, which creates an empty space for input
self.left = None
self.right = None
Define Binary Tree Class:
class BinaryTree:
# Defining Roots as Nodes, initiating at the same time.
def __init__(self, rootdata):
# Declaring roots as new nodes which uses root data
self.root = Node(rootdata)
Defining FindMax, which will find the maximum value in a binary tree, then return the maximum.
def FindMax(root):
# ???
if (root == None):
return float('-inf')
# In this function, it will search for the maximum of three values, the roots, and maximums from left and right leaves.
# Initialization of 3 things: the maximum of root, and two maximums of left and right leaves
letsfind = root.data
lfound = FindMax(root.left)
rfound = FindMax(root.right)
# If a maximum is found on the left, new maximum is the value.
if(lfound > letsfind):
letsfind = lfound
# If a maximum is found on the right, new maximum is the value.
if(rfound > letsfind):
letsfind = rfound
# Return the maximum value found.
return letsfind
???
if name == 'main':
# The Inputs of the Binary Tree and leaves.
# root (Top most), root.left (Left Leaf), root.right (Right Leaf)
root = Node(2)
root.left = Node(7)
root.right = Node(5)
root.left.right = Node(6)
root.left.right.left= Node(1)
root.left.right.right= Node(11)
root.right.right= Node(9)
root.right.right.left= Node(4)
# Print the Maximum
print("The Maximum Value in the Binary Tree is: ", FindMax(root))
I know it seems long, so I apologize.
I have taken account that the function 'FindMax' needs to be outside of the class, in order for it to run properly.
One more thing though, what is the purpose of the statement if __name__ == '__main__':?
And What is the if (root == None): return float('-inf') Really for?
Thanks a lot guys. I appreciate it! :)
lis = FindMax(start.left)
ris = FindMax(start.right)
You forgot to call the recursive search
Option 1
The problem is here
st = start.data
lis = start.left
ris = start.right
while you actually call for the data node on st. The other ones (lis and ris) are only been call as Nodes. You should change it with
st = start.data
lis = (start.left).data
ris = (start.right).data
to be reading the data from all nodes
Option 2
You override > for your node class.
Funny but a not for a rookie. If you are interested start reading this
This is the correct code:
def findMax(start):
# Base case
if start is None:
return float('-inf')
st = start.data
lis = findMax(start.left)
ris = findMax(start.right)
if (lis > st):
st = lis
if (ris > st):
st = ris
return st
and call findMax() now
Tree=BinaryTree("1")
Tree.root.left=Node("2")
Tree.root.right=Node("3")
Tree.root.left.left=Node("4")
Tree.root.left.right=Node("5")
Tree.root.right.left=Node("6")
Tree.root.right.right=Node("7")
Tree.root.right.right.right=Node("8")
print("Maximum element is", findMax(start))
def findMax(root):
if (root == None):
return float('-inf')
res = root.data
lres = findMax(root.left)
rres = findMax(root.right)
if (lres > res):
res = lres
if (rres > res):
res = rres
return res
if __name__ == '__main__':
root = newNode(2)
root.left = newNode(7)
root.right = newNode(5)
root.left.right = newNode(6)
root.left.right.left = newNode(1)
root.left.right.right = newNode(11)
root.right.right = newNode(9)
root.right.right.left = newNode(4)
print("Maximum element is", findMax(root))
#Output
Maximum element is 11
Note - There are a few exceptions to my answer:
It may contain errors as OP did not provide the BinaryTree class.
Does not take into account any logical issues.
It is focused on getting OP's code working.
Here are the errors that I spotted:
Python is a language which requires proper indentation. Indentation is vital in-order for code to function properly. It appears that the way you have indented your code is incorrect.
When you are trying to call a function inside a class, you would need to make the call either via an instance (self) or the class itself (classmethods). Explanation provided here.
Explanation of if __name__ == "__main__": here. It is not really required as I assume your code is a single module (in one Python file) but is good to have when working with multiple modules.
Based on the points I have mentioned, I have corrected your code accordingly as follows:
# Any required imports goes here...
# import XXX
class BinaryTree:
# OP did not provide code sample...
class Node:
def __init__(self, data):
# Creating a node
self.data = data
# Pointing either left or right, but it is empty in default
self.left = None
self.right = None
def fmax(self, start):
if start is None:
return 0
st = start.data
lis = self.fmax(start.left)
ris = self.fmax(start.right)
if (lis > st):
st = lis
if (ris > st):
st = ris
return st
if __name__ == "__main__":
Tree = BinaryTree("1")
Tree.root.left = Node("2")
Tree.root.right = Node("3")
Tree.root.left.left = Node("4")
Tree.root.left.right = Node("5")
Tree.root.right.left = Node("6")
Tree.root.right.right = Node("7")
Tree.root.right.right.right = Node("8")
print(Tree.fmax(Tree.root))
If anyone spots any error with my code please feel free to edit it. My idea is to get OP a working code and he can expand from there.

Recursion: Children are being added to wrong parents in iterative deepening depth first search

.getSuccessorStates(node) returns the correct successor states (children). I have tested this method on its own using the graph provided in this problem. The problem lies when I add recursion to the mix for this iterative deepening depth-first search algorithm. When I check the value of the self.parent dictionary after everything has been returned in order to backtrack and find the shortest path, some nodes in the dictionary are matched with an incorrect parent. I'm 99% sure it has to do with recursion when I store self[parent] = node, because getSuccessorStates gives the correct children for the given node, but self.parent contains some values with wrong parent to children pairings. I'm wondering if I put self.parent[child] = node in the wrong place in the code?
def __init__(self, graph):
self.graph = graph
self.nodesCreated = 0
self.maxFrontier = 0
self.maxExplored = 0
self.parent = {}
def recursive_depth_limited_search(self, node, limit):
if node == self.getGraph().getGoalState():
return node
elif limit == 0:
return "cutoff"
else:
cutoff_occurred = False
for child in self.getGraph().getSuccessorStates(node):
self.setNodesCreated(self.getNodesCreated() + 1)
self.parent[child] = node
result = self.recursive_depth_limited_search(child, limit - 1)
if result == "cutoff":
cutoff_occurred = True
elif result != "No solution found":
return result
if cutoff_occurred:
return "cutoff"
else:
return "No solution found"

Categories