Skip to content

Commit

Permalink
binary-tree added (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
czgdp1807 authored Jun 19, 2019
1 parent b0e0cc3 commit 353e34a
Show file tree
Hide file tree
Showing 6 changed files with 320 additions and 0 deletions.
1 change: 1 addition & 0 deletions pydatastructs/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .linear_data_structures import *
from .trees import *
5 changes: 5 additions & 0 deletions pydatastructs/linear_data_structures/arrays.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ class OneDimensionalArray(Array):
>>> arr[0] = 7.2
>>> arr[0]
7
References
==========
.. [1] https://en.wikipedia.org/wiki/Array_data_structure#One-dimensional_arrays
'''
def __new__(cls, dtype=NoneType, *args, **kwargs):
if dtype == NoneType or len(args) not in (1, 2):
Expand Down
7 changes: 7 additions & 0 deletions pydatastructs/trees/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
__all__ = []

from . import binary_trees
from .binary_trees import (
Node, BinaryTree, BinarySearchTree
)
__all__.extend(binary_trees.__all__)
276 changes: 276 additions & 0 deletions pydatastructs/trees/binary_trees.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
from __future__ import print_function, division

__all__ = [
'Node',
'BinaryTree',
'BinarySearchTree'
]

class Node(object):
"""
Represents node in trees.
Parameters
==========
data
Any valid data to be stored in the node.
key
Required for comparison operations.
left: int
Optional, index of the left child node.
right: int
Optional, index of the right child node.
"""

__slots__ = ['key', 'data', 'left', 'right', 'is_root']

def __new__(cls, key, data):
obj = object.__new__(cls)
obj.data, obj.key = data, key
obj.left, obj.right = None, None
obj.is_root = False
return obj

def __str__(self):
"""
Used for printing.
"""
return str((self.left, self.key, self.data, self.right))

class BinaryTree(object):
"""
Abstract binary tree.
Parameters
==========
root_data
Optional, the root node of the binary tree.
If not of type Node, it will consider
root as data and a new root node will
be created.
key
Required if tree is to be instantiated with
root otherwise not needed.
comp: lambda
Optional, A lambda function which will be used
for comparison of keys. Should return a
bool value. By default it implements less
than operator.
References
==========
.. [1] https://en.wikipedia.org/wiki/Binary_tree
"""

__slots__ = ['root_idx', 'comparator', 'tree', 'size']

def __new__(cls, key=None, root_data=None, comp=None):
obj = object.__new__(cls)
if key == None and root_data != None:
raise ValueError('Key required.')
key = None if root_data == None else key
root = Node(key, root_data)
root.is_root = True
obj.root_idx = 0
obj.tree, obj.size = [root], 1
obj.comparator = lambda key1, key2: key1 < key2 \
if comp == None else comp
return obj

def __str__(self):
return str([(node.left, node.key, node.data, node.right)
for node in self.tree])


class BinarySearchTree(BinaryTree):
"""
Represents binary search trees.
Examples
========
>>> from pydatastructs.trees import BinarySearchTree as BST
>>> b = BST()
>>> b.insert(1, 1)
>>> b.insert(2, 2)
>>> child = b.tree[b.root_idx].right
>>> b.tree[child].data
2
>>> b.search(1)
0
>>> b.search(-1) == None
True
>>> b.delete(1) == True
True
>>> b.search(1) == None
True
>>> b.delete(2) == True
True
>>> b.search(2) == None
True
References
==========
.. [1] https://en.wikipedia.org/wiki/Binary_search_tree
"""
def insert(self, key, data):
"""
Inserts data by the passed key using iterative
algorithm.
Parameters
==========
key
The key for comparison.
data
The data to be inserted.
Returns
=======
None
"""
walk = self.root_idx
if self.tree[walk].key == None:
self.tree[walk].key = key
self.tree[walk].data = data
return None
new_node = Node(key, data)
while True:
if self.tree[walk].key == key:
self.tree[walk].data = data
return None
if not self.comparator(key, self.tree[walk].key):
if self.tree[walk].right == None:
self.tree.append(new_node)
self.tree[walk].right = self.size
self.size += 1
return None
walk = self.tree[walk].right
else:
if self.tree[walk].left == None:
self.tree.append(new_node)
self.tree[walk].left = self.size
self.size += 1
return None
walk = self.tree[walk].left

def search(self, key, **kwargs):
"""
Searches for the data in the binary search tree
using iterative algorithm.
Parameters
==========
key
The key for searching.
parent: bool
If true then returns index of the
parent of the node with the passed
key.
By default, False
Returns
=======
int
If the node with the passed key is
in the tree.
tuple
The index of the searched node and
the index of the parent of that node.
None
In all other cases.
"""
ret_parent = kwargs.get('parent', False)
parent = None
walk = self.root_idx
if self.tree[walk].key == None:
return None
while walk != None:
if self.tree[walk].key == key:
break
parent = walk
if self.comparator(key, self.tree[walk].key):
walk = self.tree[walk].left
else:
walk = self.tree[walk].right
return (walk, parent) if ret_parent else walk

def delete(self, key):
"""
Deletes the data with the passed key
using iterative algorithm.
Parameters
==========
key
The key of the node which is
to be deleted.
Returns
=======
True
If the node is deleted successfully.
None
If the node to be deleted doesn't exists.
Note
====
The node is deleted means that the connection to that
node are removed but the it is still in three. This
is being done to keep the complexity of deletion, O(logn).
"""
(walk, parent) = self.search(key, parent=True)
if walk == None:
return None
if self.tree[walk].left == None and \
self.tree[walk].right == None:
if parent == None:
self.tree[self.root_idx].data = None
self.tree[self.root_idx].key = None
else:
if self.tree[parent].left == walk:
self.tree[parent].left = None
else:
self.tree[parent].right = None

elif self.tree[walk].left != None and \
self.tree[walk].right != None:
twalk = self.tree[walk].right
par = walk
while self.tree[twalk].left != None:
par = twalk
twalk = self.tree[twalk].left
self.tree[walk].data = self.tree[twalk].data
self.tree[walk].key = self.tree[twalk].key
self.tree[par].left = self.tree[twalk].right

else:
if self.tree[walk].left != None:
child = self.tree[walk].left
else:
child = self.tree[walk].right
if parent == None:
self.tree[self.root_idx].left = self.tree[child].left
self.tree[self.root_idx].right = self.tree[child].right
self.tree[self.root_idx].data = self.tree[child].data
self.tree[self.root_idx].key = self.tree[child].key
self.tree[child].left = None
self.tree[child].right = None
else:
if self.tree[parent].left == walk:
self.tree[parent].left = child
else:
self.tree[parent].right = child

return True
Empty file.
31 changes: 31 additions & 0 deletions pydatastructs/trees/tests/test_binary_trees.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from pydatastructs.trees.binary_trees import BinarySearchTree
from pydatastructs.utils.raises_util import raises

def test_BinarySearchTree():
BST = BinarySearchTree
b = BST(8, 8)
b.insert(3, 3)
b.insert(10, 10)
b.insert(1, 1)
b.insert(6, 6)
b.insert(4, 4)
b.insert(7, 7)
b.insert(14, 14)
b.insert(13, 13)
assert str(b) == \
("[(1, 8, 8, 2), (3, 3, 3, 4), (None, 10, 10, 7), (None, 1, 1, None), "
"(5, 6, 6, 6), (None, 4, 4, None), (None, 7, 7, None), (8, 14, 14, None), "
"(None, 13, 13, None)]")
assert b.search(10) == 2
assert b.search(-1) == None
assert b.delete(13) == True
assert b.search(13) == None
assert b.delete(10) == True
assert b.search(10) == None
assert b.delete(3) == True
assert b.search(3) == None
assert str(b) == \
("[(1, 8, 8, 7), (3, 4, 4, 4), (None, 10, 10, 7), (None, 1, 1, None), "
"(None, 6, 6, 6), (None, 4, 4, None), (None, 7, 7, None), (None, 14, 14, None), "
"(None, 13, 13, None)]")
raises(ValueError, lambda: BST(root_data=6))

0 comments on commit 353e34a

Please sign in to comment.