├── .gitignore ├── BinarySearchTree.py ├── BinaryTree.py ├── BinaryTreePrinter.py ├── README.md ├── Tree.py ├── ds.py └── ds2.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | __pycache__/* -------------------------------------------------------------------------------- /BinarySearchTree.py: -------------------------------------------------------------------------------- 1 | from BinaryTreePrinter import BinaryTreePrinter 2 | 3 | 4 | class Node: 5 | def __init__(self, val): 6 | self.left: Node = None 7 | self.right: Node = None 8 | self.val = val 9 | 10 | 11 | class BinarySearchTree: 12 | def __init__(self): 13 | self.root = None 14 | 15 | def insert(self, val): 16 | if self.root is None: 17 | self.root = Node(val) 18 | else: 19 | self.__insert(self.root, val) 20 | 21 | def __insert(self, node: Node, val): 22 | if node.val == val: 23 | return 24 | elif val < node.val: 25 | if node.left is None: 26 | node.left = Node(val) 27 | else: 28 | self.__insert(node.left, val) 29 | else: 30 | if node.right is None: 31 | node.right = Node(val) 32 | else: 33 | self.__insert(node.right, val) 34 | 35 | def in_order(self): 36 | self.__in_order(self.root) 37 | 38 | def __in_order(self, node: Node): 39 | if node is None: 40 | return 41 | self.__in_order(node.left) 42 | print(node.val) 43 | self.__in_order(node.right) 44 | 45 | 46 | bst = BinarySearchTree() 47 | for i in [8, 4, 12, 2, 6, 10, 16, 1, 5, 7, 100, 200, 150, 9, 15]: 48 | bst.insert(i) 49 | # bst.in_order() 50 | BinaryTreePrinter(extra_padding=2).print_node(bst.root) -------------------------------------------------------------------------------- /BinaryTree.py: -------------------------------------------------------------------------------- 1 | from ds2 import Queue 2 | from BinaryTreePrinter import BinaryTreePrinter 3 | 4 | class TreeNode: 5 | def __init__(self, val): 6 | self.left = None 7 | self.right = None 8 | self.val = val 9 | 10 | 11 | class BinaryTree: 12 | def __init__(self): 13 | self.root = None 14 | 15 | def insert(self, val): 16 | if self.root is None: 17 | self.root = TreeNode(val) 18 | else: 19 | nodes = Queue() 20 | nodes.enqueue(self.root) 21 | 22 | while True: 23 | check_node = nodes.deque() 24 | if check_node.left is None: 25 | check_node.left = TreeNode(val) 26 | return 27 | elif check_node.right is None: 28 | check_node.right = TreeNode(val) 29 | return 30 | else: 31 | nodes.enqueue(check_node.left) 32 | nodes.enqueue(check_node.right) 33 | 34 | def __str__(self): 35 | tree_printer = BinaryTreePrinter() 36 | # tree_printer = BinaryTreePrinter(branch_line="_", extra_padding=0) 37 | return tree_printer.get_tree_string(self.root) 38 | 39 | 40 | my_tree = BinaryTree() 41 | for i in [1, 2, 3, 6, 7, 12, 45, 54, 12, 45, 76, 33, 12, 11, 101]: 42 | my_tree.insert(i) 43 | print(my_tree) 44 | -------------------------------------------------------------------------------- /BinaryTreePrinter.py: -------------------------------------------------------------------------------- 1 | """ 2 | Printer Utility to print a binary tree like a tree. 3 | 4 | Can print a binary tree whose root node has at least the following properties. 5 | 6 | node.left # left child 7 | node.right # right child 8 | node.val # value of the node 9 | """ 10 | 11 | 12 | class NodePrintData: 13 | def __init__(self, lines: list, root_position, root_len): 14 | self.lines = lines 15 | self.root_position = root_position 16 | self.root_len = root_len 17 | self.max_width = 0 if len(lines) == 0 else max([len(line) for line in self.lines]) 18 | self.height = len(self.lines) 19 | 20 | 21 | class BinaryTreePrinter: 22 | def __init__(self, branch_line=".", left_node_line="/", right_node_line="\\", extra_padding=1): 23 | self.branch_line = branch_line 24 | self.left_node_line = left_node_line 25 | self.right_node_line = right_node_line 26 | self.extra_padding = extra_padding 27 | 28 | def __treeify(self, node): 29 | if node is None: 30 | return NodePrintData([], 0, 0) 31 | 32 | val = f"{node.val}" 33 | left_node_data = self.__treeify(node.left) 34 | right_node_data = self.__treeify(node.right) 35 | lines = [] 36 | first_line = "" 37 | second_line = "" 38 | len_before_val = 0 39 | if left_node_data.max_width > 0: 40 | left_root_end = left_node_data.root_len + left_node_data.root_position 41 | branch_len = left_node_data.max_width - (left_node_data.root_position + left_node_data.root_len) 42 | first_line += " " * (left_root_end + 1) 43 | first_line += self.branch_line * (branch_len + self.extra_padding) 44 | len_before_val = len(first_line) 45 | second_line += " " * left_root_end + self.left_node_line 46 | second_line += " " * (len_before_val - len(second_line)) 47 | 48 | first_line += val 49 | left_padding = "" if right_node_data.max_width == 0 else " " * (len(val) + 1 + self.extra_padding) 50 | if right_node_data.max_width > 0: 51 | first_line += self.branch_line * (right_node_data.root_position + self.extra_padding) 52 | second_line += " " * (right_node_data.root_position + len(val) + self.extra_padding) + self.right_node_line 53 | 54 | lines.append(first_line) 55 | lines.append(second_line) 56 | for i in range(max(left_node_data.height, right_node_data.height)): 57 | if i < left_node_data.height and i < right_node_data.height: 58 | left_line: str = left_node_data.lines[i] 59 | right_line: str = right_node_data.lines[i] 60 | elif i < left_node_data.height: 61 | left_line = left_node_data.lines[i] 62 | right_line = "" 63 | else: 64 | right_line = right_node_data.lines[i] 65 | left_line = "" 66 | lines.append( 67 | "{:<{l_width}}{}{:<{r_width}}".format(left_line, left_padding, right_line, l_width=len_before_val, 68 | r_width=right_node_data.max_width)) 69 | return NodePrintData(lines, len_before_val, len(val)) 70 | 71 | def print_node(self, root_node): 72 | node_data = self.__treeify(root_node) 73 | for line in node_data.lines: 74 | print(line) 75 | 76 | def get_tree_string(self, root_node): 77 | node_data = self.__treeify(root_node) 78 | return "\n".join(node_data.lines) 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DS & Algorithm 2 | Repo for DS and Algo tutorials. 3 | 4 | Tutorials: https://www.youtube.com/playlist?list=PLV3rqOvr9vgkW7U-kdxtUBx74ICpw94k8 5 | -------------------------------------------------------------------------------- /Tree.py: -------------------------------------------------------------------------------- 1 | from ds2 import Queue 2 | from ds2 import Stack 3 | from BinaryTreePrinter import BinaryTreePrinter 4 | 5 | 6 | class TreeNode: 7 | def __init__(self, val): 8 | self.left = None 9 | self.right = None 10 | self.val = val 11 | 12 | 13 | class BinaryTree: 14 | def __init__(self): 15 | self.root = None 16 | 17 | def insert(self, val): 18 | if self.root is None: 19 | self.root = TreeNode(val) 20 | else: 21 | nodes = Queue() 22 | nodes.enqueue(self.root) 23 | 24 | while True: 25 | checking_node = nodes.deque() 26 | if checking_node.left is None: 27 | checking_node.left = TreeNode(val) 28 | return 29 | elif checking_node.right is None: 30 | checking_node.right = TreeNode(val) 31 | return 32 | else: 33 | nodes.enqueue(checking_node.left) 34 | nodes.enqueue(checking_node.right) 35 | 36 | def __str__(self): 37 | tree_printer = BinaryTreePrinter() 38 | return tree_printer.get_tree_string(self.root) 39 | 40 | def contains(self, val): 41 | nodes = Stack() 42 | nodes.push(self.root) 43 | 44 | while not nodes.is_empty(): 45 | node = nodes.pop() 46 | print("Checking node:", node.val) 47 | if node.val == val: 48 | return True 49 | if node.right is not None: 50 | nodes.push(node.right) 51 | if node.left is not None: 52 | nodes.push(node.left) 53 | return False 54 | 55 | 56 | class BST: 57 | def __init__(self): 58 | self.root = None 59 | 60 | def __insert_value(self, node, value): 61 | if node is None: 62 | return 63 | 64 | if node.val == value: 65 | return 66 | elif value < node.val: 67 | if node.left is None: 68 | node.left = TreeNode(value) 69 | return 70 | self.__insert_value(node.left, value) 71 | else: 72 | if node.right is None: 73 | node.right = TreeNode(value) 74 | return 75 | self.__insert_value(node.right, value) 76 | 77 | def insert(self, val): 78 | if self.root is None: 79 | self.root = TreeNode(val) 80 | else: 81 | self.__insert_value(self.root, val) 82 | 83 | def __str__(self): 84 | tree_printer = BinaryTreePrinter() 85 | return tree_printer.get_tree_string(self.root) 86 | 87 | def __in_order(self, node): 88 | if node is None: 89 | return 90 | self.__in_order(node.left) 91 | print(node.val, end=" ") 92 | self.__in_order(node.right) 93 | 94 | def in_order(self): 95 | self.__in_order(self.root) 96 | 97 | def contains(self, val): 98 | nodes = Stack() 99 | nodes.push(self.root) 100 | 101 | while not nodes.is_empty(): 102 | node = nodes.pop() 103 | print("Checking node:", node.val) 104 | if node.val == val: 105 | return True 106 | elif val < node.val: 107 | if node.left is not None: 108 | nodes.push(node.left) 109 | else: 110 | if node.right is not None: 111 | nodes.push(node.right) 112 | return False 113 | 114 | 115 | # my_tree = BinaryTree() 116 | # for c in ['a', 'b', 'c', 'd', 'e', 'f']: 117 | # my_tree.insert(c) 118 | # print(my_tree) 119 | 120 | 121 | bst = BinaryTree() 122 | for i in [8, 2, 1, 10, 100, 50, 40, 23, 16, 7, 9, 200, 150, 300]: 123 | bst.insert(i) 124 | print(bst) 125 | 126 | # bst.in_order() 127 | print() 128 | print("Contains 10:", bst.contains(150)) 129 | print("Contains 0:", bst.contains(0)) -------------------------------------------------------------------------------- /ds.py: -------------------------------------------------------------------------------- 1 | class Node: 2 | def __init__(self, value): 3 | self.next = None 4 | self.prev = None 5 | self.val = value 6 | 7 | 8 | class DoubleLinkedList: 9 | def __init__(self): 10 | self.head = None 11 | self.tail = None 12 | self.size = 0 13 | 14 | def add(self, val): 15 | node = Node(val) 16 | if self.tail is None: 17 | self.head = node 18 | self.tail = node 19 | self.size += 1 20 | else: 21 | self.tail.next = node 22 | node.prev = self.tail 23 | self.tail = node 24 | self.size += 1 25 | 26 | def __remove_node(self, node): 27 | if node.prev is None: 28 | self.head = node.next 29 | else: 30 | node.prev.next = node.next 31 | 32 | if node.next is None: 33 | self.tail = node.prev 34 | else: 35 | node.next.prev = node.prev 36 | 37 | self.size -= 1 38 | 39 | def remove(self, value): 40 | node = self.head 41 | while node is not None: 42 | if node.val == value: 43 | self.__remove_node(node) 44 | node = node.next 45 | 46 | def remove_first(self): 47 | if self.tail is not None: 48 | self.__remove_node(self.head) 49 | 50 | def remove_last(self): 51 | if self.tail is not None: 52 | self.__remove_node(self.tail) 53 | 54 | def front(self): 55 | return self.head.val 56 | 57 | def back(self): 58 | return self.tail.val 59 | 60 | def __str__(self): 61 | vals = [] 62 | node = self.head 63 | while node is not None: 64 | vals.append(node.val) 65 | node = node.next 66 | return f"[{', '.join(str(val) for val in vals)}]" 67 | -------------------------------------------------------------------------------- /ds2.py: -------------------------------------------------------------------------------- 1 | from ds import DoubleLinkedList 2 | 3 | 4 | class Stack: 5 | def __init__(self): 6 | self.__list = DoubleLinkedList() 7 | 8 | def push(self, val): 9 | self.__list.add(val) 10 | 11 | def pop(self): 12 | val = self.__list.back() 13 | self.__list.remove_last() 14 | return val 15 | 16 | def is_empty(self): 17 | return self.__list.size == 0 18 | 19 | def peek(self): 20 | return self.__list.back() 21 | 22 | def __len__(self): 23 | return self.__list.size 24 | 25 | 26 | class Queue: 27 | def __init__(self): 28 | self.__list = DoubleLinkedList() 29 | 30 | def enqueue(self, val): 31 | self.__list.add(val) 32 | 33 | def deque(self): 34 | val = self.__list.front() 35 | self.__list.remove_first() 36 | return val 37 | 38 | def front(self): 39 | return self.__list.front() 40 | 41 | def is_empty(self): 42 | return self.__list.size == 0 43 | 44 | def __len__(self): 45 | return self.__list.size 46 | 47 | 48 | # from collections import deque 49 | # 50 | # my_queue = Queue() 51 | # my_queue.enqueue(1) 52 | # print(len(my_queue)) 53 | # print(my_queue.front()) 54 | # my_queue.enqueue(1) 55 | # my_queue.enqueue(4) 56 | # my_queue.enqueue(10) 57 | # my_queue.enqueue(111) 58 | # print(my_queue.front()) 59 | # print(len(my_queue)) 60 | # print(my_queue.deque()) 61 | # print(my_queue.front()) 62 | # my_queue.deque() 63 | # print(my_queue.front()) 64 | 65 | --------------------------------------------------------------------------------