Remaing Daa
Remaing Daa
DESCRIPTION:
The program constructs a binary tree based on user input and then performs pre-order traversal on the constructed
tree. Pre-order traversal visits each node in the tree in the order: current node, left subtree, right subtree.
ALGORITHM:
1. Define a class TreeNode to represent a node in the binary tree. Each node has a value and references to its left
and right children.
2. Define a function build_tree() to construct the binary tree. This function prompts the user to enter the value
of each node. If the user enters an empty value, it indicates a null node.
• Prompt the user to enter the value of the root node.
• If the entered value is empty, return None (indicating a null node).
• Otherwise, create a new TreeNode with the entered value as its value.
• Recursively call build_tree() to construct the left and right subtrees, then assign them to the left and
right children of the current node.
• Return the constructed root node.
3. Define a function pre_order_traversal(root) to perform pre-order traversal on the binary tree. This function
takes the root node of the tree as input.
• If the root node is None, return.
• Print the value of the current node.
• Recursively call pre_order_traversal() on the left subtree.
• Recursively call pre_order_traversal() on the right subtree.
TIME COMPLEXITY:
The time complexity of the provided code is ( O(n) , where n is the number of nodes in the binary tree. This
complexity arises from the pre-order traversal operation, which visits each node once. The building of the binary tree
also contributes to the time complexity, but it is overshadowed by the traversal operation. Therefore, the overall time
complexity is O(n) .
PROGRAM CODE:
class TreeNode:
self.val = value
self.left = None
self.right = None
def build_tree():
if not root_val:
return None
root = TreeNode(int(root_val))
print(f"Enter the left child of {root.val} (Enter empty value to indicate a null node):")
root.left = build_tree()
print(f"Enter the right child of {root.val} (Enter empty value to indicate a null node):")
root.right = build_tree()
return root
def pre_order_traversal(root):
if root is None:
return
pre_order_traversal(root.left)
pre_order_traversal(root.right)
if __name__ == "__main__":
print("Enter the elements of the tree (Enter empty value to indicate a null node):")
root = build_tree()
pre_order_traversal(root)
EXPECTED OUTPUT:
Enter the elements of the tree (Enter empty value to indicate a null node):
Enter the left child of 20 (Enter empty value to indicate a null node):
Enter the left child of 34 (Enter empty value to indicate a null node):
Enter the left child of 56 (Enter empty value to indicate a null node):
Enter the right child of 56 (Enter empty value to indicate a null node):
Enter the left child of 78 (Enter empty value to indicate a null node):
Enter the right child of 78 (Enter empty value to indicate a null node):
Enter the right child of 34 (Enter empty value to indicate a null node):
Enter the left child of 30 (Enter empty value to indicate a null node):
Enter the right child of 30 (Enter empty value to indicate a null node):
Enter the right child of 20 (Enter empty value to indicate a null node):
Enter the left child of 10 (Enter empty value to indicate a null node):
Enter the right child of 10 (Enter empty value to indicate a null node):
20 34 56 78 30 10
EXECUTED OUTPUT:
RESULT: The above Python program To Perform the traversal algorithms for a given tree in a Pre order is executed
successfully.
AIM: Python program Perform the traversal algorithms for a given tree in a Post order.
DESCRIPTION:
This Python program performs post-order traversal for a given binary tree. Post-order traversal visits each node in the
tree in the order: left subtree, right subtree, current node. The program takes input from the user to construct the
binary tree and then performs the post-order traversal..
ALGORITHM:
1. Define a class TreeNode to represent a node in the binary tree. Each node has a value and references to its left
and right children.
2. Define a function build_tree() to construct the binary tree recursively. This function prompts the user to enter
the value of each node. If the user enters an empty value, it indicates a null node.
3. Define a function post_order_traversal(root) to perform post-order traversal on the binary tree. This function
takes the root node of the tree as input.
• If the root node is None, return.
• Recursively call post_order_traversal() on the left subtree.
• Recursively call post_order_traversal() on the right subtree.
• Print the value of the current node.
TIME COMPLEXITY:
The time complexity of this program is (O(n), where n is the number of nodes in the binary tree. This is because each
node is visited exactly once during the post-order traversal.
PROGRAM CODE:
class TreeNode:
self.val = value
self.left = None
self.right = None
def build_tree():
if not root_val:
return None
root = TreeNode(int(root_val))
print(f"Enter the left child of {root.val} (Enter empty value to indicate a null node):")
root.left = build_tree()
print(f"Enter the right child of {root.val} (Enter empty value to indicate a null node):")
root.right = build_tree()
return root
def post_order_traversal(root):
if root is None:
return
post_order_traversal(root.left)
post_order_traversal(root.right)
# Main function
if __name__ == "__main__":
print("Enter the elements of the tree (Enter empty value to indicate a null node):")
root = build_tree()
post_order_traversal(root)
EXPECTED OUTPUT:
Enter the elements of the tree (Enter empty value to indicate a null node):
Enter the left child of 20 (Enter empty value to indicate a null node):
Enter the left child of 10 (Enter empty value to indicate a null node):
Enter the right child of 10 (Enter empty value to indicate a null node):
Enter the left child of 30 (Enter empty value to indicate a null node):
Enter the left child of 5 (Enter empty value to indicate a null node):
Enter the right child of 5 (Enter empty value to indicate a null node):
Enter the right child of 30 (Enter empty value to indicate a null node):
Enter the right child of 20 (Enter empty value to indicate a null node):
Enter the left child of 90 (Enter empty value to indicate a null node):
Enter the left child of 20 (Enter empty value to indicate a null node):
Enter the left child of 32 (Enter empty value to indicate a null node):
Enter the right child of 32 (Enter empty value to indicate a null node):
Enter the right child of 20 (Enter empty value to indicate a null node):
Enter the left child of 43 (Enter empty value to indicate a null node):
Enter the right child of 43 (Enter empty value to indicate a null node):
Enter the right child of 90 (Enter empty value to indicate a null node):
5 30 10 32 43 20 90 20
EXECUTED OUTPUT:
RESULT: The above Python program To Perform the traversal algorithms for a given tree in a POST order is executed
successfully.
DESCRIPTION:
This Python program performs in-order traversal for a given binary tree. In-order traversal visits each node in the tree
in the order: left subtree, current node, right subtree. The program takes input from the user to construct the binary
tree and then performs the in-order traversal.
ALGORITHM:
1. Define a class TreeNode to represent a node in the binary tree. Each node has a value and references to its
left and right children.
2. Define a function build_tree() to construct the binary tree recursively. This function prompts the user to enter
the value of each node. If the user enters an empty value, it indicates a null node.
3. Define a function in_order_traversal(root) to perform in-order traversal on the binary tree. This function
takes the root node of the tree as input.
• If the root node is None, return.
• Recursively call in_order_traversal() on the left subtree.
• Print the value of the current node.
• Recursively call in_order_traversal() on the right subtree.
TIME COMPLEXITY:
The time complexity of this program is O(n), where n is the number of nodes in the binary tree. This is because each
node is visited exactly once during the in-order traversal..
PROGRAM CODE:
class TreeNode:
self.val = value
self.left = None
self.right = None
def build_tree():
if not root_val:
return None
root = TreeNode(int(root_val))
print(f"Enter the left child of {root.val} (Enter empty value to indicate a null node):")
root.left = build_tree()
print(f"Enter the right child of {root.val} (Enter empty value to indicate a null node):")
root.right = build_tree()
return root
def in_order_traversal(root):
if root is None:
return
in_order_traversal(root.left)
in_order_traversal(root.right)
if __name__ == "__main__":
print("Enter the elements of the tree (Enter empty value to indicate a null node):")
root = build_tree()
in_order_traversal(root)
EXPECTED OUTPUT:
Enter the elements of the tree (Enter empty value to indicate a null node):
Enter the left child of 1 (Enter empty value to indicate a null node):
Enter the left child of 3 (Enter empty value to indicate a null node):
Enter the right child of 3 (Enter empty value to indicate a null node):
Enter the right child of 1 (Enter empty value to indicate a null node):
Enter the left child of 4 (Enter empty value to indicate a null node):
Enter the right child of 4 (Enter empty value to indicate a null node):
314
EXECUTED OUTPUT:
RESULT: The above Python program To Perform the traversal algorithms for a given tree in a IN order is executed
successfully.
AIM : To Write A Python Program To Find The Job Sequence With Deadline.
DESCRIPTION :
The program aims to find the maximum profit sequence of jobs within their deadlines, given the details of each job
(job name, deadline, and profit) and the number of time slots available. It uses a greedy approach, sorting the jobs
based on their profit in decreasing order and then scheduling them based on their deadlines and available time slots.
ALGORITHM:
• Input: Take input from the user for the number of jobs, details of each job (job name, deadline, and profit),
and the number of time slots available.
• Sorting: Sort all jobs according to decreasing order of profit.
• Initialization: Initialize an array result of size t to keep track of free time slots and an array job of size t to
store the sequence of jobs scheduled within the available time slots.
• Scheduling Jobs: Iterate through all given jobs.
• For each job, find a free time slot starting from the last possible slot before its deadline.
• Assign the job to the first available time slot and mark the time slot as occupied.
• Output: Print the sequence of jobs scheduled within the available time slots.
TIME COMPLEXITY:
Sorting Jobs: Sorting all jobs based on their profit requires O(nlogn) time, where n is the number of jobs.
Scheduling Jobs: Iterating through all jobs and finding free time slots for each job takes O(n⋅t) time, where
Total Time Complexity: The overall time complexity of the program is dominated by the sorting step, so it is O(nlogn),
where n is the number of jobs.
The time complexity of the program mainly depends on the number of jobs and the number of time slots available.
Sorting the jobs based on profit takes the most significant amount of time, making the overall time complexity
O(nlogn).
PROGRAM CODE:
arr = []
for i in range(n):
result = [False] * t
job = ['-1'] * t
for i in range(len(arr)):
if result[j] is False:
result[j] = True
job[j] = arr[i][0]
break
print(job)
EXPECTED OUTPUT:
EXECUTED OUTPUT:
RESULT: The above Python Program To Find The Job Sequence With Deadline is executed successfully
AIM :
DESCRIPTION :
The Sum of Subsets problem involves finding subsets of a set whose sum is equal to a given target
sum. This problem is solved using backtracking, where decisions are made incrementally to include or
exclude elements from the set.
ALOGIRTHM :
• Initialization :
Start with an empty solution subset and begin exploring from the first element of the set.
Base Case : If the current subset's sum equals the target sum, print the subset as a solution.
• Recursive Case :
Include the current element in the subset if adding it does not exceed the target sum.
Backtrack by removing the current element from the subset and explore the option of excluding it.
• Result :
After exploring all possible subsets, the algorithm prints or collects all subsets whose sum equals the
target sum.
TIME COMPLEXITY :
The time complexity of the backtracking algorithm depends on the number of solutions and the
complexity of checking each solution.
In the worst case, all subsets need to be explored, leading to an exponential time complexity O(2N),
where N is the number of elements in the set.
SAPCE COMPLEXITY :
The space complexity is O(N) due to the recursion depth of the backtracking function and the space
required for storing the current subset.
PROGRAM CODE :
if sum_so_far == target_sum:
solutions.append(subset[:])
return
# If we've reached the end of the set or exceeded the target sum, return
return
subset.append(set[n-1])
subset.pop()
def read_input():
def main():
solutions = []
if not solutions:
else:
print("Subsets found:")
print(subset)
if __name__ == "__main__":
main()
EXPECTED OUTPUT :
Subsets found:
[5]
[4, 1]
[3, 2]
EXECUTED OUTPUT :
RESULT :
The above program to implement sum of subsets problem using backtracking executed successfully.
AIM :
DESCRIPTION :
The N Queens problem involves placing N chess queens on an N×N chessboard so that no two
queens attack each other. This means that no two queens should share the same row, column, or diagonal.
ALOGIRTHM :
• Initialization :
Use an array cols where cols[row] represents the column index of the queen placed in row row.
Base Case : If all queens are placed successfully (i.e., row == N), print the board configuration.
• Recursive Case :
Iterate through each column (col) for the current row (row).
Ensure no other queen shares the same column (col), diagonal (both main diagonal and anti-
diagonal).
If safe, mark (row, col) as part of the solution (cols[row] = col) and recursively call the function for
the next row (row + 1).
Backtrack by undoing the placement if placing a queen does not lead to a solution.
• Result :
After exploring all possible placements, the algorithm prints all distinct solutions (or counts them,
depending on the implementation).
TIME COMPLEXITY :
SPACE COMPLEXITY :
The space complexity is O(N)due to the space required for the cols array to store the column
positions of queens for each row.
PROGRAM CODE :
for i in range(col):
if board[row][i] == 1:
return False
if board[i][j] == 1:
return False
if board[i][j] == 1:
return False
return True
return True
for i in range(len(board)):
if is_safe(board, i, col):
board[i][col] = 1
return True
board[i][col] = 0
return False
def print_solution(board):
def nqueens():
else:
print_solution(board)
nqueens()
EXPECTED OUTPUT :
Q.......
......Q.
....Q...
.......Q
.Q......
...Q....
.....Q..
..Q.....
EXECUTED OUTPUT :
RESULT :
The above program to implement N-Queen’s problem using BackTracking executed successfully.
AIM :
DESCRIPTION :
The graph coloring problem involves assigning colors to the vertices of a graph such that no two
adjacent vertices share the same color. The goal is to use the minimum number of colors to color the graph.
This is a common problem in computer science and can be applied in various fields such as scheduling, map
coloring, and register allocation in compilers.
ALGORITHM :
• For each adjacent vertex, if it has the same color, return False.
o For each color, check if it is safe to assign that color using is_safe.
o If it is safe, assign the color and recursively call graph_coloring_util for the next vertex.
o If no color can be assigned, backtrack by removing the color (reset to 0) and try the next
color.
• Call the utility function graph_coloring_util with the initial vertex (0).
• Take manual input for the number of vertices, the adjacency matrix, and the number of colors.
TIME COMPLEXITY :
SPACE COMPLEXITY :
O(V), where V is the number of vertices, due to the recursion stack and the color array.
PROGRAM CODE :
for i in range(len(graph)):
return False
return True
if v == len(graph):
return True
color[v] = c
return True
color[v] = 0
return False
return color
# Manual input
def main():
V = int(input())
graph = []
for i in range(V):
graph.append(row)
m = int(input())
result = graph_coloring(graph, m)
print(result)
else:
print(result)
if __name__ == "__main__":
main()
EXPECTED OUTPUT :
0111
1010
1101
1010
[1, 2, 3, 2]
EXECUTED OUTPUT :
RESULT :
The above program to implement Graph coloring problem using BackTracking executed successfully.
AIM :
DESCRIPTION :
A Hamiltonian graph is a graph that contains a Hamiltonian cycle. A Hamiltonian cycle (or
Hamiltonian circuit) is a cycle that visits each vertex exactly once and returns to the starting vertex.
Determining whether such a cycle exists in a given graph is known as the Hamiltonian Cycle problem, which
is NP-complete.
ALGORITHM :
Recursive utility function. Create a recursive function that takes the current position in the path.
Base Case. If all vertices are included in the path, check if there is an edge from the last included vertex to
the starting vertex.
Try different vertices. For each vertex, check if it can be added to the Hamiltonian Cycle. If so, add the
vertex to the path and call the recursive function.
Backtrack. If adding a vertex does not lead to a solution, remove it from the path and try the next vertex.
Return the path if a Hamiltonian Cycle is found. If the function returns true, the Hamiltonian Cycle is found.
TIME COMPLEXITY :
The time complexity of this algorithm is O(N!), where N is the number of vertices. This is because it
explores all possible permutations of vertices to find the Hamiltonian Cycle.
SPACE COMPLEXITY :
The space complexity is O(N) for the path array plus the space used by the recursion stack, which
also has a maximum depth of O(N). Thus, the overall space complexity is O(N).
PROGRAM CODE :
if graph[path[pos - 1]][v] == 0:
return False
if v in path:
return False
return True
if pos == len(graph):
return True
path[pos] = v
return True
path[pos] = -1
return False
def hamiltonian_path(graph):
path[0] = 0
return False
return True
graph = []
for i in range(n):
graph.append(row)
hamiltonian_path(graph)
EXPECTED OUTPUT :
0110
1011
1101
0110
EXECUTED OUTPUT :
RESULT :
The above program to implement Hamiltonian graph problem using BackTracking executed
successfully.
AIM :
DESCRIPTION :
The 0/1 knapsack problem can be solved using backtracking. The goal is to find the maximum total
value of items that can be placed in a knapsack of given capacity, where each item can either be taken or
not (hence 0/1).
ALGORITHM :
• Initialize Inputs :
Read the number of items, their values, weights, and the capacity of the knapsack.
• Base Case : If the number of items is 0 or the capacity is 0, return 0.
• Recursive Case :
If the weight of the current item is more than the remaining capacity, exclude the item and
recursively solve the problem for the remaining items.
Otherwise, solve the problem in two ways :
➢ Include the current item: Add its value to the total and reduce the capacity by its weight.
Recursively solve for the remaining items and updated capacity.
➢ Exclude the current item: Recursively solve for the remaining items without changing the
capacity.
• Return the maximum value obtained from the above two cases.
• Compute and Print Result :
Compute the maximum value that can be obtained and print it.
TIME COMPLEXITY :
The time complexity of the backtracking approach to the 0/1 knapsack problem is 𝑂(2^𝑛), where 𝑛 is
the number of items. This is because for each item, there are two possibilities (include or exclude), leading
to a total of 2𝑛 possible subsets.
SPACE COMPLEXITY :
The space complexity is 𝑂(𝑛), which is the maximum depth of the recursion tree (equal to the
number of items). This space is used by the call stack due to the recursive calls. Each recursive call uses
constant space, and the maximum depth of recursion is 𝑛.
PROGRAM CODE :
if n == 0 or capacity == 0:
return 0
# If weight of the nth item is more than knapsack capacity, it cannot be included
else:
values = []
weights = []
for i in range(num_items):
values.append(value)
weights.append(weight)
EXPECTED OUTPUT :
EXECUTED OUTPUT :
RESULT :
The above program to implement 0/1 Knapsack problem using BackTracking executed successfully.