Update binary_search_tree.py (#1339)

* Update binary_search_tree.py

remove some bugs

* Update binary_search_tree.py

* Update binary_search_tree.py

* Update binary_search_tree.py

* Update binary_search_tree.py

* Update binary_search_tree.py

* Update binary_search_tree.py

* testlist = (8, 3, 6, 1, 10, 14, 13, 4, 7)

* Update .travis.yml

Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
Hocnonsense 2019-12-21 08:44:31 +08:00 committed by Christian Clauss
parent 3242682473
commit 81ae5adcc8
2 changed files with 163 additions and 219 deletions

View File

@ -6,6 +6,7 @@ install: pip install -r requirements.txt
before_script: before_script:
- black --check . || true - black --check . || true
- flake8 . --count --select=E101,E9,F4,F63,F7,F82,W191 --show-source --statistics - flake8 . --count --select=E101,E9,F4,F63,F7,F82,W191 --show-source --statistics
- flake8 . --count --exit-zero --max-line-length=127 --statistics
script: script:
- scripts/validate_filenames.py # no uppercase, no spaces, in a directory - scripts/validate_filenames.py # no uppercase, no spaces, in a directory
- mypy --ignore-missing-imports . - mypy --ignore-missing-imports .

View File

@ -1,204 +1,157 @@
""" '''
A binary search Tree A binary search Tree
""" '''
class Node: class Node:
def __init__(self, label, parent): def __init__(self, value, parent):
self.label = label self.value = value
self.parent = parent # Added in order to delete a node easier
self.left = None self.left = None
self.right = None self.right = None
# Added in order to delete a node easier
self.parent = parent
def getLabel(self): def __repr__(self):
return self.label from pprint import pformat
def setLabel(self, label):
self.label = label
def getLeft(self):
return self.left
def setLeft(self, left):
self.left = left
def getRight(self):
return self.right
def setRight(self, right):
self.right = right
def getParent(self):
return self.parent
def setParent(self, parent):
self.parent = parent
if self.left is None and self.right is None:
return str(self.value)
return pformat(
{
"%s"
% (self.value): (self.left, self.right)
},
indent=1,
)
class BinarySearchTree: class BinarySearchTree:
def __init__(self): def __init__(self, root = None):
self.root = None self.root = root
# Insert a new node in Binary Search Tree with value label def __str__(self):
def insert(self, label): """
# Create a new Node Return a string of all the Nodes using in order traversal
new_node = Node(label, None) """
# If Tree is empty return str(self.root)
if self.empty():
self.root = new_node
else:
# If Tree is not empty
curr_node = self.root
# While we don't get to a leaf
while curr_node is not None:
# We keep reference of the parent node
parent_node = curr_node
# If node label is less than current node
if new_node.getLabel() < curr_node.getLabel():
# We go left
curr_node = curr_node.getLeft()
else:
# Else we go right
curr_node = curr_node.getRight()
# We insert the new node in a leaf
if new_node.getLabel() < parent_node.getLabel():
parent_node.setLeft(new_node)
else:
parent_node.setRight(new_node)
# Set parent to the new node
new_node.setParent(parent_node)
def delete(self, label): def __reassign_nodes(self, node, newChildren):
if not self.empty(): if(newChildren is not None): # reset its kids
# Look for the node with that label newChildren.parent = node.parent
node = self.getNode(label) if(node.parent is not None): # reset its parent
# If the node exists if(self.is_right(node)): # If it is the right children
if node is not None: node.parent.right = newChildren
# If it has no children
if node.getLeft() is None and node.getRight() is None:
self.__reassignNodes(node, None)
node = None
# Has only right children
elif node.getLeft() is None and node.getRight() is not None:
self.__reassignNodes(node, node.getRight())
# Has only left children
elif node.getLeft() is not None and node.getRight() is None:
self.__reassignNodes(node, node.getLeft())
# Has two children
else: else:
# Gets the max value of the left branch node.parent.left = newChildren
tmpNode = self.getMax(node.getLeft()) else:
# Deletes the tmpNode self.root = newChildren
self.delete(tmpNode.getLabel())
# Assigns the value to the node to delete and keesp tree structure
node.setLabel(tmpNode.getLabel())
def getNode(self, label): def is_right(self, node):
curr_node = None return node == node.parent.right
# If the tree is not empty
if not self.empty():
# Get tree root
curr_node = self.getRoot()
# While we don't find the node we look for
# I am using lazy evaluation here to avoid NoneType Attribute error
while curr_node is not None and curr_node.getLabel() is not label:
# If node label is less than current node
if label < curr_node.getLabel():
# We go left
curr_node = curr_node.getLeft()
else:
# Else we go right
curr_node = curr_node.getRight()
return curr_node
def getMax(self, root=None):
if root is not None:
curr_node = root
else:
# We go deep on the right branch
curr_node = self.getRoot()
if not self.empty():
while curr_node.getRight() is not None:
curr_node = curr_node.getRight()
return curr_node
def getMin(self, root=None):
if root is not None:
curr_node = root
else:
# We go deep on the left branch
curr_node = self.getRoot()
if not self.empty():
curr_node = self.getRoot()
while curr_node.getLeft() is not None:
curr_node = curr_node.getLeft()
return curr_node
def empty(self): def empty(self):
if self.root is None: return self.root is None
return True
return False
def __InOrderTraversal(self, curr_node): def __insert(self, value):
nodeList = [] """
if curr_node is not None: Insert a new node in Binary Search Tree with value label
nodeList.insert(0, curr_node) """
nodeList = nodeList + self.__InOrderTraversal(curr_node.getLeft()) new_node = Node(value, None) # create a new Node
nodeList = nodeList + self.__InOrderTraversal(curr_node.getRight()) if self.empty(): # if Tree is empty
return nodeList self.root = new_node # set its root
else: # Tree is not empty
def getRoot(self): parent_node = self.root # from root
return self.root while True: # While we don't get to a leaf
if value < parent_node.value: # We go left
def __isRightChildren(self, node): if parent_node.left == None:
if node == node.getParent().getRight(): parent_node.left = new_node # We insert the new node in a leaf
return True break
return False
def __reassignNodes(self, node, newChildren):
if newChildren is not None:
newChildren.setParent(node.getParent())
if node.getParent() is not None:
# If it is the Right Children
if self.__isRightChildren(node):
node.getParent().setRight(newChildren)
else: else:
# Else it is the left children parent_node = parent_node.left
node.getParent().setLeft(newChildren) else:
if parent_node.right == None:
# This function traversal the tree. By default it returns an parent_node.right = new_node
# In order traversal list. You can pass a function to traversal break
# The tree as needed by client code else:
def traversalTree(self, traversalFunction=None, root=None): parent_node = parent_node.right
if traversalFunction is None: new_node.parent = parent_node
# Returns a list of nodes in preOrder by default
return self.__InOrderTraversal(self.root) def insert(self, *values):
for value in values:
self.__insert(value)
return self
def search(self, value):
if self.empty():
raise IndexError("Warning: Tree is empty! please use another. ")
else:
node = self.root
# use lazy evaluation here to avoid NoneType Attribute error
while node is not None and node.value is not value:
node = node.left if value < node.value else node.right
return node
def get_max(self, node = None):
"""
We go deep on the right branch
"""
if node is None:
node = self.root
if not self.empty():
while(node.right is not None):
node = node.right
return node
def get_min(self, node = None):
"""
We go deep on the left branch
"""
if(node is None):
node = self.root
if(not self.empty()):
node = self.root
while(node.left is not None):
node = node.left
return node
def remove(self, value):
node = self.search(value) # Look for the node with that label
if(node is not None):
if(node.left is None and node.right is None): # If it has no children
self.__reassign_nodes(node, None)
node = None
elif(node.left is None): # Has only right children
self.__reassign_nodes(node, node.right)
elif(node.right is None): # Has only left children
self.__reassign_nodes(node, node.left)
else:
tmpNode = self.get_max(node.left) # Gets the max value of the left branch
self.remove(tmpNode.value)
node.value = tmpNode.value # Assigns the value to the node to delete and keesp tree structure
def preorder_traverse(self, node):
if node is not None:
yield node # Preorder Traversal
yield from self.preorder_traverse(node.left)
yield from self.preorder_traverse(node.right)
def traversal_tree(self, traversalFunction = None):
"""
This function traversal the tree.
You can pass a function to traversal the tree as needed by client code
"""
if(traversalFunction is None):
return self.preorder_traverse(self.root)
else: else:
# Returns a list of nodes in the order that the users wants to
return traversalFunction(self.root) return traversalFunction(self.root)
# Returns an string of all the nodes labels in the list def postorder(curr_node):
# In Order Traversal """
def __str__(self): postOrder (left, right, self)
list = self.__InOrderTraversal(self.root) """
str = "" nodeList = list()
for x in list:
str = str + " " + x.getLabel().__str__()
return str
def InPreOrder(curr_node):
nodeList = []
if curr_node is not None: if curr_node is not None:
nodeList = nodeList + InPreOrder(curr_node.getLeft()) nodeList = postorder(curr_node.left) + postorder(curr_node.right) + [curr_node]
nodeList.insert(0, curr_node.getLabel())
nodeList = nodeList + InPreOrder(curr_node.getRight())
return nodeList return nodeList
def binary_search_tree():
def testBinarySearchTree(): r'''
r"""
Example Example
8 8
/ \ / \
@ -207,56 +160,46 @@ def testBinarySearchTree():
1 6 14 1 6 14
/ \ / / \ /
4 7 13 4 7 13
"""
r""" >>> t = BinarySearchTree().insert(8, 3, 6, 1, 10, 14, 13, 4, 7)
Example After Deletion >>> print(" ".join(repr(i.value) for i in t.traversal_tree()))
7 8 3 1 6 4 7 10 14 13
/ \ >>> print(" ".join(repr(i.value) for i in t.traversal_tree(postorder)))
1 4 1 4 7 6 3 13 14 10 8
>>> BinarySearchTree().search(6)
""" Traceback (most recent call last):
...
IndexError: Warning: Tree is empty! please use another.
'''
testlist = (8, 3, 6, 1, 10, 14, 13, 4, 7)
t = BinarySearchTree() t = BinarySearchTree()
t.insert(8) for i in testlist:
t.insert(3) t.insert(i)
t.insert(6)
t.insert(1)
t.insert(10)
t.insert(14)
t.insert(13)
t.insert(4)
t.insert(7)
# Prints all the elements of the list in order traversal # Prints all the elements of the list in order traversal
print(t.__str__()) print(t)
if t.getNode(6) is not None: if(t.search(6) is not None):
print("The label 6 exists") print("The value 6 exists")
else: else:
print("The label 6 doesn't exist") print("The value 6 doesn't exist")
if t.getNode(-1) is not None: if(t.search(-1) is not None):
print("The label -1 exists") print("The value -1 exists")
else: else:
print("The label -1 doesn't exist") print("The value -1 doesn't exist")
if not t.empty(): if(not t.empty()):
print(("Max Value: ", t.getMax().getLabel())) print("Max Value: ", t.get_max().value)
print(("Min Value: ", t.getMin().getLabel())) print("Min Value: ", t.get_min().value)
t.delete(13) for i in testlist:
t.delete(10) t.remove(i)
t.delete(8) print(t)
t.delete(3)
t.delete(6)
t.delete(14)
# Gets all the elements of the tree In pre order
# And it prints them
list = t.traversalTree(InPreOrder, t.root)
for x in list:
print(x)
二叉搜索树 = binary_search_tree
if __name__ == "__main__": if __name__ == "__main__":
testBinarySearchTree() import doctest
doctest.testmod()
binary_search_tree()