Skip to content

Commit

Permalink
refactor: moved TreeNodes from {Tree}Node to datastax/Nodes/
Browse files Browse the repository at this point in the history
  • Loading branch information
warmachine028 committed Aug 3, 2023
1 parent 021baa1 commit 4a6da8d
Show file tree
Hide file tree
Showing 19 changed files with 625 additions and 17 deletions.
21 changes: 21 additions & 0 deletions datastax/Nodes/AVLNode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from typing import Any, Self, Optional
from datastax.Nodes.TreeNode import TreeNode


class AVLNode(TreeNode):
_height = 1

def __init__(self, data: Any,
left: Optional[Self] = None,
right: Optional[Self] = None):
super().__init__(data, left, right)

@property
def height(self):
return self._height

def set_height(self, height: int):
if isinstance(height, int):
self._height = height
return
raise TypeError("The 'height' parameter must be an integer")
6 changes: 5 additions & 1 deletion datastax/Nodes/AbstractNodes/DoublyNode.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from abc import ABC as AbstractClass
from abc import ABC as AbstractClass, abstractmethod
from typing import Optional, Self

from datastax.Nodes.AbstractNodes.Node import Node
Expand Down Expand Up @@ -27,3 +27,7 @@ def __str__(self):
)
dow = f" └────╨{'─' * width}╨────┘\n"
return top + mid + dow

@abstractmethod
def set_prev(self, prev: Self):
...
80 changes: 80 additions & 0 deletions datastax/Nodes/AbstractNodes/HuffmanNode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from datastax.Nodes.AbstractNodes.TreeNode import TreeNode
from datastax.Utils import Commons
from abc import ABC as AbstractClass, abstractmethod


class HuffmanNode(TreeNode, AbstractClass):
_frequency: int

@property
def frequency(self):
return self._frequency

def __str__(self):
values = [
self.data or self.frequency,
self.left.data or self.left.frequency if self.left else None,
self.right.data or self.right.frequency if self.right else None,
]
values = list(
map(
lambda value: "" if value is None else Commons.repr(value),
values
)
)
max_width = max(len(Commons.repr(data)) for data in values if data)
if max_width % 2:
max_width += 1 # To make max_width even

"Building string from calculated values"
per_piece = 2 * (max_width + 4)
string_builder = f"{Commons.node_builder(values[0], per_piece)}\n"
per_piece //= 2
hpw = int(per_piece // 2 - 1)
if any(values[1:]):
if all(values[1:]):
string_builder += (
f"{' ' * (hpw + 1)}" f"┌{'─' * hpw}{'─' * hpw}\n"
)
string_builder += (
Commons.node_builder(values[1], per_piece)
+ Commons.node_builder(values[2], per_piece)
)
elif values[1]:
string_builder += f"{' ' * (hpw + 1)}{'─' * hpw}\n"
string_builder += Commons.node_builder(values[1], per_piece)
else:
string_builder += f"{' ' * (per_piece - 1)}{'─' * hpw}\n"
string_builder += (
f"{' ' * (per_piece - 1)} "
f"{Commons.node_builder(values[2], per_piece)}"
)

return string_builder

def preorder_print(self) -> None:
values = [
self.data or self.frequency,
self.left.data or self.left.frequency if self.left else None,
self.right.data or self.right.frequency if self.right else None,
]
values = list(
map(
lambda value: "" if value is None else Commons.repr(value),
values
)
)

string_builder = f"{values[0]}\n"
if any(values[1:]):
if all(values[1:]):
string_builder += f"├─▶ {values[1]}\n"
string_builder += f"└─▶ {values[2]}"
else:
string_builder += f"└─▶ {values[1] or values[2]}"

print(string_builder)

@abstractmethod
def set_frequency(self, frequency: int):
...
4 changes: 2 additions & 2 deletions datastax/Nodes/AbstractNodes/Node.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


class Node(AbstractClass):
data: Optional[Any]
data: Any
_next: Optional[Self]

@property
Expand All @@ -22,5 +22,5 @@ def __str__(self):
return top + mid + dow

@abstractmethod
def set_next(self, _next: Optional[Self]):
def set_next(self, _next: Self):
...
106 changes: 106 additions & 0 deletions datastax/Nodes/AbstractNodes/RedBlackNode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from typing import Self, Optional
from datastax.Nodes.AbstractNodes.TreeNode import TreeNode
from datastax.Utils import Commons, Colors
from abc import ABC as AbstractClass, abstractmethod

fore, back, reset = Colors.FORE, Colors.BACK, Colors.RESET
red, black, grey = Colors.RED, Colors.BLACK, Colors.GREY


class RedBlackNode(TreeNode, AbstractClass):
_parent: Optional[Self] = None
_color: int

@property
def parent(self):
return self._parent

@property
def color(self):
return self._color

def __str__(self):
values = list(
map(
lambda node: "" if node is None else Commons.format(
node.color, Commons.repr(node.data)
), [self, self.left, self.right]
)
)
max_width = max(
len(Commons.repr(data)) - 33 for data in values if data
)
max_width += max_width % 2 # To make max_width even
padding = 4
per_piece = 2 * (max_width + padding)
extra_line = f"{back}{grey}{' ' * (per_piece + 1)}{reset}\n"

string_builder = (
f"{extra_line}"
f"{back}{grey}"
f"{Commons.redblack_node_builder(values[0], per_piece)} "
f"{reset}\n{back}{grey}"
)
per_piece //= 2
hpw = int(per_piece // 2 - 1)
if any(values[1:]):
if all(values[1:]):
part = f"{' ' * (hpw + 1)}{'─' * hpw}{'─' * hpw}┐"
string_builder += (
f"{part}{' ' * (len(part) - per_piece - 1)}"
f"{reset}\n{back}{grey}"
)
string_builder += Commons.redblack_node_builder(
values[1], per_piece
) + Commons.redblack_node_builder(
values[2], per_piece
)
elif values[1]:
part = f"{' ' * (hpw + 1)}{'─' * hpw}{' ' * hpw}"
string_builder += (
f"{part}{' ' * (len(part) - per_piece - 1)}"
f"{reset}\n{back}{grey}"
)
string = Commons.redblack_node_builder(values[1], per_piece)
string_builder += f"{string}{' ' * (len(string) - 33)}"
else:
part = f"{' ' * (per_piece - 1)}{'─' * hpw}┐"
string_builder += (
f"{part}{' ' * (len(part) - per_piece - 1)}"
f"{reset}\n{back}{grey}"
)
string_builder += (
f"{' ' * (per_piece - 1)} "
f"{Commons.redblack_node_builder(values[2], per_piece)}"
)
string_builder += f" {reset}\n{extra_line}"
return string_builder

def preorder_print(self) -> None:
values = list(
map(
lambda node: "" if node is None else Commons.format(
node.color, Commons.repr(node.data)
), [self, self.left, self.right]
)
)
string_builder = f'\n{back}{grey}{values[0]} {reset}\n'
if any(values[1:]):
if all(values[1:]):
string_builder += (
f"{back}{grey}├─▶ {values[1]} {reset}\n"
f"{back}{grey}└─▶ {values[2]} {reset}\n"
)
else:
data = values[1] or values[2]
string_builder += f"{back}{grey}└─▶ {data} {reset}\n"

print(string_builder)

@abstractmethod
def set_parent(self, parent: Self):
...

@abstractmethod
def set_color(self, color: int):
...
15 changes: 15 additions & 0 deletions datastax/Nodes/AbstractNodes/SegmentNode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from datastax.Nodes.AbstractNodes.TreeNode import TreeNode
from abc import ABC as AbstractClass


class SegmentNode(TreeNode, AbstractClass):
left_index: int
right_index: int

def __str__(self):
# to be overriden and implemented later
return super().__str__()

def preorder_print(self) -> None:
# to be overriden and implemented later
super().preorder_print()
106 changes: 106 additions & 0 deletions datastax/Nodes/AbstractNodes/ThreadedNode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from datastax.Utils import Commons
from datastax.Nodes.AbstractNodes.TreeNode import TreeNode
from abc import ABC as AbstractClass, abstractmethod


class ThreadedNode(TreeNode, AbstractClass):
_left_is_child: bool
_right_is_child: bool

@property
def left_is_child(self):
return self._left_is_child

@property
def right_is_child(self):
return self._right_is_child

def __str__(self):
values = [
self.data if self.data is not None else str(None),
self.left.data if self.left else None,
self.right.data if self.right else None
]
values = list(
map(lambda value: Commons.repr(value), values)
)
max_width = max(len(Commons.repr(data)) for data in values if data)
if max_width % 2:
max_width += 1 # To make max_width even

padding = 6
per_piece = 2 * (max_width + padding)
# Building the part first
wpn = per_piece // 2 - 1
wpn = (wpn + 1) if wpn % 2 else wpn
piece = '┴'.center(wpn, '─')
piece = f"{'┌' if self.left_is_child else '└'}{piece[:-1]}"
piece = f"{piece}{'┐' if self.right_is_child else '┘'}"
piece = f"{piece.center(wpn)}\n"

root = values[0]
left = f"{values[1]}"
right = f"{values[2].center(wpn + 1)}\n"

if self.left_is_child:
if self.right_is_child:
string_builder = (
f"{root.center(wpn - 1)}".center(per_piece) +
f"\n{piece}{left}{right}"
)
else:
string_builder = (
f"{' ' * len(left)}\n"
f"{root.center(wpn)}".center(wpn - 1) +
f"│\n{piece}"
f"{left}"
)
else:
string_builder = left
if self.right_is_child:
string_builder = (
f"\n{root.center(wpn)}".center(per_piece) +
f"\n{piece}{' ' * len(left)}"
f"\n{' ' * len(left)}{right}"
)
else:
string_builder = (
f"{right}"
f"│{root.center(wpn - 1)}│".center(per_piece) +
f"\n{piece}"
)

return string_builder

def preorder_print(self) -> None:
values = [
self.data if self.data is not None else str(None),
self.left.data if self.left else None,
self.right.data if self.right else None
]
values = list(
map(
lambda value: str(value) if value is None else Commons.repr(
value
),
values
)
)

string_builder = f'{values[0]}\n'
if any(values[1:]):
if all(values[1:]):
string_builder += f"├─▶ {values[1]}\n"
string_builder += f"└─▶ {values[2]}"
else:
string_builder += f"└─▶ {values[1] or values[2]}"

print(string_builder)

@abstractmethod
def set_left_is_child(self, is_child: bool):
...

@abstractmethod
def set_right_is_child(self, is_child: bool):
...
Loading

0 comments on commit 4a6da8d

Please sign in to comment.