Skip to content

Commit

Permalink
refactor: changed datastax/trees to datastax/Trees
Browse files Browse the repository at this point in the history
  • Loading branch information
warmachine028 committed Aug 3, 2023
1 parent 93e3b46 commit 021baa1
Show file tree
Hide file tree
Showing 27 changed files with 1,149 additions and 1,562 deletions.
76 changes: 33 additions & 43 deletions datastax/Trees/avl_tree.py → datastax/Trees/AVLTree.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,33 @@
# AVL Tree Implementation (Also: Self Balancing Binary Tree)
from __future__ import annotations

import warnings
from typing import Any, Optional

from datastax.errors import DuplicateNodeWarning
from datastax.Trees.binary_search_tree import BinarySearchTree, TreeNode


class AVLNode(TreeNode):
def __init__(self, data: Any,
left: AVLNode = None,
right: AVLNode = None):
super().__init__(data, left, right)
self.height = 1
from datastax.Utils.Warnings import DuplicateNodeWarning
from datastax.Trees.BinarySearchTree import BinarySearchTree
from datastax.Nodes import AVLNode


class AVLTree(BinarySearchTree):
def __init__(self, array: list[Any] = None, root=None):
self._root: Optional[AVLNode] = root
super().__init__(array, root)
def __init__(self, items: Optional[list] = None,
root: Optional[AVLNode] = None):
self.set_root(root)
super().__init__(items, root)

# Private helper method for insert function
def _place(self, parent: Optional[AVLNode], data) -> Optional[AVLNode]:
def _place(self, parent: AVLNode | None, data) -> AVLNode | None:
if not parent:
return AVLNode(data)
if parent.data < data:
parent.right = self._place(parent.right, data)
parent.set_right(self._place(parent.right, data))
elif data < parent.data:
parent.left = self._place(parent.left, data)
parent.set_left(self._place(parent.left, data))
else:
warnings.warn(
f"Insertion unsuccessful. Item '{data}' already exists "
"in AVLTree", DuplicateNodeWarning
)
parent.height = 1 + max(
parent.set_height(1 + max(
self.height(parent.left),
self.height(parent.right)
)
))
# Balancing the tree
return self._balance(parent)

Expand All @@ -50,11 +40,11 @@ def balance_factor(self, parent: Optional[AVLNode] = None) -> int:

# Function to get height of a tree
@staticmethod
def height(node: Optional[AVLNode]) -> int:
def height(node: AVLNode | None) -> int:
return node.height if node else 0

# Function to balance a node
def _balance(self, parent: Optional[AVLNode]) -> Optional[AVLNode]:
def _balance(self, parent: AVLNode | None) -> AVLNode | None:
if not parent:
return None
balance_factor = self.balance_factor(parent)
Expand All @@ -66,7 +56,7 @@ def _balance(self, parent: Optional[AVLNode]) -> Optional[AVLNode]:
# Perform RL Rotation
else:
if parent.right:
parent.right = self._right_rotate(parent.right)
parent.set_right(self._right_rotate(parent.right))
return self._left_rotate(parent)

if balance_factor > 1:
Expand All @@ -77,41 +67,41 @@ def _balance(self, parent: Optional[AVLNode]) -> Optional[AVLNode]:
# Perform LR Rotation
else:
if parent.left:
parent.left = self._left_rotate(parent.left)
parent.set_left(self._left_rotate(parent.left))
return self._right_rotate(parent)
return parent

# Private helper method of balance function to perform RR rotation
def _right_rotate(self, node: AVLNode) -> Optional[AVLNode]:
def _right_rotate(self, node: AVLNode) -> AVLNode | None:
left = node.left
if left:
temp = left.right
left.right = node
node.left = temp
node.height = 1 + max(self.height(node.left),
self.height(node.right))
left.height = 1 + max(self.height(left.left),
self.height(left.right))
left.set_right(node)
node.set_left(temp)
node.set_height(1 + max(self.height(node.left),
self.height(node.right)))
left.set_height(1 + max(self.height(left.left),
self.height(left.right)))
return left

# Private helper method of balance function to perform LL rotation
def _left_rotate(self, node: AVLNode) -> Optional[AVLNode]:
def _left_rotate(self, node: AVLNode) -> AVLNode | None:
right = node.right
if right:
temp = right.left
right.left = node
node.right = temp
node.height = 1 + max(self.height(node.left),
self.height(node.right))
right.height = 1 + max(self.height(right.left),
self.height(right.right))
right.set_left(node)
node.set_right(temp)
node.set_height(1 + max(self.height(node.left),
self.height(node.right)))
right.set_height(1 + max(self.height(right.left),
self.height(right.right)))
return right

def _delete(self, root: Optional[AVLNode], item: Any) -> Optional[AVLNode]:
def _delete(self, root: AVLNode | None, item: Any) -> AVLNode | None:
root = super()._delete(root, item)
if root:
root.height = 1 + max(
root.set_height(1 + max(
self.height(root.left),
self.height(root.right)
)
))
return self._balance(root)
135 changes: 135 additions & 0 deletions datastax/Trees/AbstractTrees/BinaryTree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import math
from typing import Any, Optional
from datastax.Nodes import TreeNode
from datastax.Lists import Queue
from datastax.Utils import Commons
from abc import ABC as AbstractClass, abstractmethod


class BinaryTree(AbstractClass):
_root: Optional[TreeNode]
_string: Optional[str]

@property
def root(self):
return self._root

@property # Level Order Traversal -> Tree to array
def array_repr(self) -> list[Any]:
array = []
queue = Queue()
if self.root:
queue.enqueue(self.root)
while not queue.is_empty():
node = queue.dequeue()
array.append(node.data)
if node.left:
queue.enqueue(node.left)
if node.right:
queue.enqueue(node.right)

return array

# Level order Traversal of Tree
def __str__(self):
root = self.root
if not root:
return " NULL"

lines = []
level = [root]
nodes = 1
max_width = 0
while nodes:
line = []
next_level = []
nodes = 0
for node in level:
if node:
data = Commons.repr(node.data)
max_width = max(len(data), max_width)
line.append(data)
next_level += [node.left, node.right]
if node.left:
nodes += 1
if node.right:
nodes += 1
continue
line.append(None)
next_level += [None] * 2
if max_width % 2:
max_width += 1
lines.append(line)
level = next_level
##################################################################
"Building string from calculated values"
per_piece = len(lines[-1]) * (max_width + 4)

string_builder = f"{Commons.node_builder(lines[0][0], per_piece)}\n"
per_piece //= 2
for _, line in enumerate(lines[1:], 1):
hpw = int(math.floor(per_piece / 2) - 1)
# Printing ┌ ┴ ┐ or ┌ ─ ┘ or └ ─ ┐ components
for j, value in enumerate(line):
string_builder += (
(
("┴" if value else "┘")
if line[j - 1]
else ("└" if value else " ")
)
if j % 2
else " "
)

if not value:
string_builder += " " * (per_piece - 1)
continue
if j % 2:
string_builder += f"{'─' * hpw}{' ' * hpw}"
else:
string_builder += f"{' ' * hpw}{'─' * hpw}"
string_builder += "\n"

# Printing the value of each Node
for value in line:
string_builder += Commons.node_builder(value, per_piece)
string_builder += "\n"
per_piece //= 2

return string_builder

# Pre Order Traversal of Tree
def preorder_print(self) -> None:
def string_builder(parent: Optional[TreeNode], has_right_child: bool,
padding="", component="") -> None:
if not parent:
return
if self._string is not None:
self._string += (
f"\n{padding}{component}" f"{Commons.repr(parent.data)}"
)
if parent is not root:
padding += "│ " if has_right_child else " "
left_pointer = "├─▶ " if parent.right else "└─▶ "
right_pointer = "└─▶ "
string_builder(
parent.left, bool(parent.right), padding, left_pointer
)
string_builder(parent.right, False, padding, right_pointer)

root = self.root
if not root:
self._string = "NULL"
print(self._string)
return
self._string = ""
string_builder(root, bool(root.right))
print(self._string)

@abstractmethod
def insert(self, item: Any):
...

@abstractmethod
def set_root(self, root: TreeNode):
...
Loading

0 comments on commit 021baa1

Please sign in to comment.