-
Notifications
You must be signed in to change notification settings - Fork 0
/
redblack-2.py
146 lines (129 loc) · 5 KB
/
redblack-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import matplotlib.pyplot as plt
import networkx as nx
import pydot
from networkx.drawing.nx_pydot import graphviz_layout
class Node:
def __init__(self, data):
self.data = data
self.color = 'RED' # New nodes are always red
self.left = None
self.right = None
self.parent = None
class RedBlackTree:
def __init__(self):
self.NIL_LEAF = Node(None)
self.NIL_LEAF.color = 'BLACK'
self.root = self.NIL_LEAF
def rotate_left(self, node):
right_child = node.right
node.right = right_child.left
if right_child.left != self.NIL_LEAF:
right_child.left.parent = node
right_child.parent = node.parent
if node.parent is None:
self.root = right_child
elif node == node.parent.left:
node.parent.left = right_child
else:
node.parent.right = right_child
right_child.left = node
node.parent = right_child
def rotate_right(self, node):
left_child = node.left
node.left = left_child.right
if left_child.right != self.NIL_LEAF:
left_child.right.parent = node
left_child.parent = node.parent
if node.parent is None:
self.root = left_child
elif node == node.parent.right:
node.parent.right = left_child
else:
node.parent.left = left_child
left_child.right = node
node.parent = left_child
def fix_insert(self, node):
while node != self.root and node.parent.color == 'RED':
if node.parent == node.parent.parent.left:
uncle = node.parent.parent.right
if uncle.color == 'RED':
node.parent.color = 'BLACK'
uncle.color = 'BLACK'
node.parent.parent.color = 'RED'
node = node.parent.parent
else:
if node == node.parent.right:
node = node.parent
self.rotate_left(node)
node.parent.color = 'BLACK'
node.parent.parent.color = 'RED'
self.rotate_right(node.parent.parent)
else:
uncle = node.parent.parent.left
if uncle.color == 'RED':
node.parent.color = 'BLACK'
uncle.color = 'BLACK'
node.parent.parent.color = 'RED'
node = node.parent.parent
else:
if node == node.parent.left:
node = node.parent
self.rotate_right(node)
node.parent.color = 'BLACK'
node.parent.parent.color = 'RED'
self.rotate_left(node.parent.parent)
self.root.color = 'BLACK'
def insert(self, data):
new_node = Node(data)
new_node.left = self.NIL_LEAF
new_node.right = self.NIL_LEAF
parent = None
current = self.root
while current != self.NIL_LEAF:
parent = current
if new_node.data < current.data:
current = current.left
else:
current = current.right
new_node.parent = parent
if parent is None:
self.root = new_node
elif new_node.data < parent.data:
parent.left = new_node
else:
parent.right = new_node
new_node.color = 'RED'
self.fix_insert(new_node)
def inorder_traversal(self, node):
if node != self.NIL_LEAF:
self.inorder_traversal(node.left)
print(f'{node.data} ({node.color})', end=' ')
self.inorder_traversal(node.right)
def visualize(self):
G = nx.DiGraph()
labels = {}
self._build_visual(self.root, G, labels)
pos = graphviz_layout(G, prog="dot") # Tree-like layout using pydot and graphviz
colors = [G.nodes[n]['color'] for n in G.nodes]
nx.draw(G, pos, labels=labels, node_color=colors, with_labels=True, node_size=1500, font_size=10, font_color='white')
plt.show()
def _build_visual(self, node, G, labels):
if node != self.NIL_LEAF:
G.add_node(node.data, color='red' if node.color == 'RED' else 'black')
labels[node.data] = node.data
if node.left != self.NIL_LEAF:
G.add_edge(node.data, node.left.data)
if node.right != self.NIL_LEAF:
G.add_edge(node.data, node.right.data)
self._build_visual(node.left, G, labels)
self._build_visual(node.right, G, labels)
# Example usage of the RedBlackTree class:
if __name__ == '__main__':
tree = RedBlackTree()
elements = [20, 15, 25, 10, 5, 1, 17, 22, 27,8,99,101,7,2,33,34,35,103,77,78,79]
for element in elements:
tree.insert(element)
print("Inorder traversal of the Red-Black Tree:")
tree.inorder_traversal(tree.root)
print("\nVisualizing Red-Black Tree:")
tree.visualize()