Advertisement
wigsinator

BinTree and BST

Mar 29th, 2017
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.57 KB | None | 0 0
  1. # A binary search tree example
  2. # Ref. Internet, StackOverflow forum
  3.  
  4. # Extensively edited by G. Fleischer, 8/8/13, 3/15/14, 3/22/14
  5.  
  6. # This class is still incomplete as of 3/22/14: it lacks
  7. ##  an erase_tree method.
  8.  
  9. ##************************************
  10. ## eraseTree method implemented 4/18/16
  11.  
  12. SPACE = " "*3
  13.  
  14. from random import randint # for testing purposes
  15.  
  16. class Node:    
  17.     """ Attributes: left , right, data  """
  18.     ##left , right, data = None, None, 0
  19.        
  20.     def __init__(self, data):
  21.         self.left = None
  22.         self.right = None
  23.         self.data = data
  24.  
  25.     def isLeaf(self):
  26.         return self.left is None and self.right is None
  27.    
  28. class BinTree:
  29.     """Binary Tree"""
  30.    
  31.     def __init__(self, root = None):
  32.         """ Creates empty tree """
  33.        
  34.         self.root = root
  35.         self.size = 1 if root else 0
  36.        
  37.  
  38.  
  39.     def addNode(self, data):
  40.             # creates a new treenode linked (rt or lf) to self
  41.             self.size += 1
  42.             return Node(data)
  43.  
  44.     def printRevTree(self, root, dep):
  45.         """Prettyprints the contents of subtree rooted at node "root" in reverse inorder"""
  46.        
  47.         if root and self.size: #only print nonempty tree. Note lazy evaluation
  48.        
  49.             self.printRevTree(root.right,dep+1) #dep param.added by G.F.8/8/13
  50.             if root.data is not None: # may not be necessary in the end
  51.                 print( SPACE * dep,root.data)
  52.             self.printRevTree(root.left,dep+1)
  53.  
  54.  
  55.     # ***************************
  56.     # Trying erase
  57.     # Algorithm: delete each leaf in Postorder
  58.  
  59.     def eraseTree(self, root): # Added 4/18/16 by G.F.
  60.         if root:
  61.             if root.isLeaf():
  62.                 print("Deleting",root.data)
  63.                 root = None
  64.             else:
  65.                 self.eraseTree(root.left)
  66.                 self.eraseTree(root.right)
  67.                 print("Deleting",root.data)
  68.                 root = None
  69.        
  70.  
  71. class BST(BinTree):
  72.     """ Binary Search Tree"""    
  73.    
  74.  
  75.     def insert(self, root, data):
  76.    
  77.             # inserts a new data value in the correct location in the search tree
  78.             # No duplication allowed
  79.            
  80.             if root is None: #We have just passed a leaf node, or started in
  81.                     ## an empty tree
  82.                     # if tree is empty, creates root node with the
  83.                     # data value, otherwise hangs new node in the correct
  84.                     # direction (R/L)  from the last leaf
  85.  
  86.                 return self.addNode(data)
  87.             else:
  88.                 # Insert into nonempty tree
  89.                 if data < root.data:
  90.                 # insert into the left sub-tree
  91.                     root.left = self.insert(root.left, data)
  92.                 elif data > root.data:
  93.                 # insert into the right sub-tree
  94.                     root.right = self.insert(root.right, data)
  95.                 # else value already in tree, ignored
  96.                
  97.                 return root
  98.            
  99.     def lookup(self, root, target, schDep = [0]):
  100.  
  101.         """ Returns True iff target value found, and side-effects a search-depth global"""
  102.  
  103.         ## schDep is a list of one element, to make it a reference var
  104.         # looks for a value into the tree
  105.         # Side effect on global var. searchDepth!
  106.  
  107.         schDep[0] += 1
  108.        
  109.         if root is None: # leaf reached without a find, or tree is empty
  110.             return False
  111.         else:
  112.                 # if it has found it...
  113.             if target == root.data:
  114.                 return True
  115.             else:
  116.                 if target < root.data:
  117.                         # continue searching in left subTree
  118.                     return self.lookup(root.left, target,schDep)
  119.                 else:
  120.                         # continue searching in right subtree
  121.                     return self.lookup(root.right, target,schDep)
  122.    
  123.     def findMin(self, node):
  124.             # goes down into the left
  125.             # subtree of given node and returns the last value
  126.         while(node.left):
  127.             node = node.left
  128.         return node.data
  129.  
  130.     def height(self, root):
  131.         """ Define height of tree as -1 for empty tree,
  132. 0 for single node tree, and the larger of the heights of LST and RST
  133. """
  134.         if root is None:
  135.             return -1
  136.         else:
  137.             lheight = self.height(root.left)
  138.             rheight = self.height(root.right)
  139.             return 1 + max(lheight, rheight)
  140.                        
  141.     def _size(self, root):
  142.         """ Returns total number of nodes in the tree."""  #Built in redundancy
  143.         if root is None:
  144.             return 0
  145.         else:
  146.             return self._size(root.left) + 1 + self._size(root.right)
  147.  
  148.     def locate(self, root, target):
  149.         """Partially duplicates the work of lookup, but returns two pointers
  150. prev and current. Current is the node with data = target, prev its parent node """
  151.         ## this method is only called if we know that target is in the tree
  152.        
  153.         prev = root
  154.         current = root
  155.         while current.data != target:
  156.             prev = current
  157.             if target < current.data:
  158.                 current = current.left
  159.                 prev.left = current
  160.             else: # target  > current.data
  161.                 current = current.right
  162.                 prev.right = current
  163.         return prev, current # Tuple (ordered pair) is returned
  164.  
  165.     def delete(self, root, target):
  166.         """Deletes the node with data value == target
  167. (while preserving the BST structure) """
  168.  
  169.         ## if target value not in tree, report and stop
  170.  
  171.         if self.size == 0:
  172.             print("Attempting to delete from empty tree")
  173.             return # No result
  174.        
  175.         if not self.lookup(root, target):
  176.             print("Tree has no node with data value", target)
  177.             return root
  178.        
  179.    
  180.         self.size -= 1
  181.         prev, current = self.locate(root, target)
  182.         ## Post-Condition: current.data == target
  183.         #DEBUG
  184.         print(prev.data, current.data)
  185.        
  186.         if current.isLeaf():
  187.             if prev.left is current: prev.left = None
  188.             else: prev.right = None
  189.             current = None
  190.  
  191.             return root # We are done
  192.        
  193.         # otherwise current has at most one child.
  194.        
  195.         # Case of exactly one child
  196.         if current.left is None: # there is a right child only
  197.             if prev.right is current: #current is right child of prev
  198.                 prev.right = current.right
  199.                 current.right = None
  200.                 current = None
  201.             elif prev.left is current:
  202.                 prev.left = current.right
  203.                 current.right = None
  204.                 current = None
  205.  
  206.             elif prev is current: ## target is at the root of the tree
  207.                 assert current is root
  208.                 if current is not root: raise AssertionError ("current should equal the root")
  209.  
  210.                 # DEBUG
  211.                 print("Deleting  root with right branch only")
  212.                
  213.                 current = root.right
  214.                 root.right = None
  215.                 root = current                
  216.                 prev = current = None
  217.                
  218.             return root # We are done
  219.            
  220.         elif current.right is None: # there is a left child only
  221.             if prev.right is current: #current is right child of prev
  222.                 prev.right = current.left
  223.                 current.left = None
  224.                 current = None
  225.             elif prev.left is current: # current is left child of prev
  226.                 prev.left = current.left
  227.                 current.left = None
  228.                 current = None
  229.  
  230.                
  231.                
  232.             elif prev is current: ## target is at the root of the tree
  233.                 assert current is root
  234.                 if current is not root: raise AssertionError ("current should equal the root")
  235.  
  236.                 # DEBUG
  237.                 print("Deleting  root with left branch only")        
  238.  
  239.                 current = root.left
  240.                 root.left = None
  241.                 root = current                
  242.                 prev = current = None                
  243.                
  244.  
  245.             return root # We are done
  246.                
  247.         ## End case of exactly one child of current
  248.  
  249.         else: # current has two children
  250.             ## Find the leftmost descendant of current's right child
  251.             # = the logical successor of current in inOrder
  252.  
  253.             ## Strategy: the Pipeline Technique
  254.  
  255.             temp = current.right
  256.             temp_prev = temp
  257.  
  258.             if temp.left is None: ## Right child IS the logical successor
  259.                 current.right = temp.right
  260.                                  
  261.             else:                    
  262.                 ## Find leftmost child of temp                
  263. ##                while temp.left is not None:
  264.                 while temp.left:
  265.                     temp_prev = temp
  266.                     temp = temp.left
  267.                 # Leftmost descendant of right child is now located.
  268.                                
  269.                 temp_prev.left = temp.right # works even if temp is a leaf
  270.  
  271.             ## Ready for the key step
  272.             # Overwrite target with data field of leftmost descendant
  273.             # of right child.
  274.             current.data = temp.data
  275.            
  276.             # Now unconditionally remove all temporary references
  277.             temp.right = None
  278.             temp.left = None #superfluous?
  279.             temp = None
  280.  
  281.             prev = current = None
  282.  
  283.             return root              
  284.                    
  285.            
  286.    
  287.  
  288.     def printTree(self, root):
  289.         ##Inorder traversal [G.F.]
  290.        
  291.         if root is not None:
  292.             self.printTree(root.left)
  293.             print( root.data, end = ' ')
  294.             self.printTree(root.right)
  295.  
  296.    
  297.        
  298.  
  299.  
  300. ###                     ******* Test runs *******
  301. print("Type go(<int>) to start")
  302. def go(numNodes = 0):
  303.    
  304.     if __name__ == "__main__":
  305.         # create the binary tree
  306.         if numNodes == 0:
  307.             print("Empty tree")
  308.             return
  309.        
  310.         DEPTH = 1 #Used in prettyprinting. G.F. 8/8/13
  311.         searchDepth = [0] # value side-effected by search function
  312.  
  313.         testData = []
  314.                  
  315.         while len(testData) < numNodes:
  316.             n =  randint(1,3 * numNodes)
  317.             if n not in testData:
  318.                 testData.append(n)
  319.  
  320.         print("Data came in the following random order:")
  321.         print(testData)
  322.    
  323. ##        bTree = BST()
  324. ##        # add the root node
  325. ##        theRoot = bTree.addNode(testData[0])
  326.  
  327.         theRoot = Node(testData[0])
  328.         bTree = BST( theRoot )
  329.        
  330.         # Enter the random data into the tree, or ask the user to insert values
  331.         for i in range(1, numNodes):
  332.             #data = int(input("insert the node value nr %d: " % i))
  333.    
  334.             data = testData[i]
  335.             # insert values
  336.             bTree.insert(theRoot, data)
  337.         print("\n\tTree contents in sorted order :\n\t",end=' ')  
  338.         bTree.printTree(theRoot); print()
  339.        
  340.         print("Tree, prettyprinted:\n\t")
  341.         bTree.printRevTree(theRoot,DEPTH)
  342.        
  343.         data = int(input("Value to find: ") )
  344.         if bTree.lookup(theRoot, data, searchDepth):
  345.             print( data, "found in %d trials" % (searchDepth[0]) )
  346.         else:
  347.             print(data, "not found")
  348.                  
  349.         print("Minimum value stored :", bTree.findMin(theRoot))
  350.         print("Height of tree: ", bTree.height(theRoot))
  351.         print("Size of tree :", bTree.size)
  352.  
  353.         print("\nInserting more nodes, then print")
  354.  
  355.         while True:
  356.             num = int(input("Type a value to insert, 0 to stop: "))
  357.             if num == 0 : break
  358.             else:
  359.                 bTree.insert(theRoot, num)
  360.                 bTree.printRevTree(theRoot,DEPTH)
  361.  
  362.         while bTree.size > 0:
  363.             num = int(input("\nType a value to delete, 0 to stop: "))
  364.             if num == 0 : break
  365.             else:
  366.                 theRoot = bTree.delete(theRoot, num)
  367.                 print("Current size of tree:",bTree.size)
  368.                 bTree.printRevTree(theRoot,DEPTH)
  369.         if bTree:
  370.             yes_no = input("The tree is still not empty. Erase?")
  371.             if yes_no[0].upper() == 'Y':
  372.                 bTree.eraseTree(theRoot)
  373.                
  374.            
  375.  
  376. ##        bTree.erase(theRoot)
  377. ##        bTree.printRevTree(theRoot,DEPTH)
  378. ##
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement