diff --git a/data_structures/binary_tree/basic_binary_tree.py b/data_structures/binary_tree/basic_binary_tree.py index 65dccf247b51..7695688b4c34 100644 --- a/data_structures/binary_tree/basic_binary_tree.py +++ b/data_structures/binary_tree/basic_binary_tree.py @@ -12,89 +12,103 @@ def __init__(self, data: int) -> None: self.right: Node | None = None -def display(tree: Node | None) -> None: # In Order traversal of the tree +class BinaryTree: """ - >>> root = Node(1) - >>> root.left = Node(0) - >>> root.right = Node(2) - >>> display(root) - 0 - 1 - 2 - >>> display(root.right) - 2 + A BinaryTree has a root node and methods for creating and manipulating binary trees. """ - if tree: - display(tree.left) - print(tree.data) - display(tree.right) - -def depth_of_tree(tree: Node | None) -> int: - """ - Recursive function that returns the depth of a binary tree. - - >>> root = Node(0) - >>> depth_of_tree(root) - 1 - >>> root.left = Node(0) - >>> depth_of_tree(root) - 2 - >>> root.right = Node(0) - >>> depth_of_tree(root) - 2 - >>> root.left.right = Node(0) - >>> depth_of_tree(root) - 3 - >>> depth_of_tree(root.left) - 2 - """ - return 1 + max(depth_of_tree(tree.left), depth_of_tree(tree.right)) if tree else 0 - - -def is_full_binary_tree(tree: Node) -> bool: + def __init__(self, root_data: int) -> None: + self.root = Node(root_data) + + def display(self, tree: Node | None) -> None: + """ + In Order traversal of the tree + >>> tree = BinaryTree(1) + >>> tree.root.left = Node(0) + >>> tree.root.right = Node(2) + >>> tree.display(tree.root) + 0 + 1 + 2 + >>> tree.display(tree.root.right) + 2 + """ + if tree: + self.display(tree.left) + print(tree.data) + self.display(tree.right) + + def depth_of_tree(self, tree: Node | None) -> int: + """ + Recursive function that returns the depth of a binary tree. + >>> tree = BinaryTree(0) + >>> tree.depth_of_tree(tree.root) + 1 + >>> tree.root.left = Node(0) + >>> tree.depth_of_tree(tree.root) + 2 + >>> tree.root.right = Node(0) + >>> tree.depth_of_tree(tree.root) + 2 + >>> tree.root.left.right = Node(0) + >>> tree.depth_of_tree(tree.root) + 3 + >>> tree.depth_of_tree(tree.root.left) + 2 + """ + return ( + 1 + max(self.depth_of_tree(tree.left), self.depth_of_tree(tree.right)) + if tree + else 0 + ) + + def is_full_binary_tree(self, tree: Node) -> bool: + """ + Returns True if this is a full binary tree + >>> tree = BinaryTree(0) + >>> tree.is_full_binary_tree(tree.root) + True + >>> tree.root.left = Node(0) + >>> tree.is_full_binary_tree(tree.root) + False + >>> tree.root.right = Node(0) + >>> tree.is_full_binary_tree(tree.root) + True + >>> tree.root.left.left = Node(0) + >>> tree.is_full_binary_tree(tree.root) + False + >>> tree.root.right.right = Node(0) + >>> tree.is_full_binary_tree(tree.root) + False + """ + if not tree: + return True + if tree.left and tree.right: + return self.is_full_binary_tree(tree.left) and self.is_full_binary_tree( + tree.right + ) + else: + return not tree.left and not tree.right + + +def main() -> None: """ - Returns True if this is a full binary tree - - >>> root = Node(0) - >>> is_full_binary_tree(root) - True - >>> root.left = Node(0) - >>> is_full_binary_tree(root) - False - >>> root.right = Node(0) - >>> is_full_binary_tree(root) - True - >>> root.left.left = Node(0) - >>> is_full_binary_tree(root) - False - >>> root.right.right = Node(0) - >>> is_full_binary_tree(root) - False + Main function for testing. """ - if not tree: - return True - if tree.left and tree.right: - return is_full_binary_tree(tree.left) and is_full_binary_tree(tree.right) - else: - return not tree.left and not tree.right - - -def main() -> None: # Main function for testing. - tree = Node(1) - tree.left = Node(2) - tree.right = Node(3) - tree.left.left = Node(4) - tree.left.right = Node(5) - tree.left.right.left = Node(6) - tree.right.left = Node(7) - tree.right.left.left = Node(8) - tree.right.left.left.right = Node(9) - - print(is_full_binary_tree(tree)) - print(depth_of_tree(tree)) + 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.left.right.left = Node(6) + tree.root.right.left = Node(7) + tree.root.right.left.left = Node(8) + tree.root.right.left.left.right = Node(9) + + print(tree.is_full_binary_tree(tree.root)) + print(tree.depth_of_tree(tree.root)) print("Tree is: ") - display(tree) + tree.display(tree.root) if __name__ == "__main__": diff --git a/dynamic_programming/knapsack.py b/dynamic_programming/knapsack.py index 489b5ada450a..3010021a3ca9 100644 --- a/dynamic_programming/knapsack.py +++ b/dynamic_programming/knapsack.py @@ -7,20 +7,19 @@ """ -def mf_knapsack(i, wt, val, j): +def mf_knapsack(i, wt, val, j, f): """ This code involves the concept of memory functions. Here we solve the subproblems which are needed unlike the below example F is a 2D array with -1s filled up """ - global f # a global dp table for knapsack if f[i][j] < 0: if j < wt[i - 1]: - val = mf_knapsack(i - 1, wt, val, j) + val = mf_knapsack(i - 1, wt, val, j, f) else: val = max( - mf_knapsack(i - 1, wt, val, j), - mf_knapsack(i - 1, wt, val, j - wt[i - 1]) + val[i - 1], + mf_knapsack(i - 1, wt, val, j, f), + mf_knapsack(i - 1, wt, val, j - wt[i - 1], f) + val[i - 1], ) f[i][j] = val return f[i][j] @@ -36,7 +35,7 @@ def knapsack(w, wt, val, n): else: dp[i][w_] = dp[i - 1][w_] - return dp[n][w_], dp + return dp[n][w], dp def knapsack_with_example_solution(w: int, wt: list, val: list): @@ -91,6 +90,7 @@ def knapsack_with_example_solution(w: int, wt: list, val: list): ) raise TypeError(msg) + f = [[0] * (w + 1)] + [[0] + [-1] * (w + 1) for _ in range(num_items + 1)] optimal_val, dp_table = knapsack(w, wt, val, num_items) example_optional_set: set = set() _construct_solution(dp_table, wt, num_items, w, example_optional_set) @@ -137,10 +137,17 @@ def _construct_solution(dp: list, wt: list, i: int, j: int, optimal_set: set): wt = [4, 3, 2, 3] n = 4 w = 6 - f = [[0] * (w + 1)] + [[0] + [-1] * (w + 1) for _ in range(n + 1)] optimal_solution, _ = knapsack(w, wt, val, n) print(optimal_solution) - print(mf_knapsack(n, wt, val, w)) # switched the n and w + print( + mf_knapsack( + n, + wt, + val, + w, + [[0] * (w + 1)] + [[0] + [-1] * (w + 1) for _ in range(n + 1)], + ) + ) # switched the n and w # testing the dynamic programming problem with example # the optimal subset for the above example are items 3 and 4