A complete binary tree is a tree in which each level has all of its nodes.
To find the parent of any node in the tree, we can simply use Python’s integer division. Given that a node is at position n in the list, the parent is at position n//2.
The Heap Order Property
In a heap, for every node x with parent p, the key in p is smaller than or equal to the key in x.
Binary Tree Applications
Parse trees can be used to represent real-world constructions like sentences or mathematical expressions.
Tree Traversals
preorder: In a preorder traversal, we visit the root node first, then recursively do a preorder traversal of the left subtree, followed by a recursive preorder traversal of the right subtree.
inorder: In an inorder traversal, we recursively do an inorder traversal on the left subtree, visit the root node, and finally do a recursive inorder traversal of the right subtree.
postorder: In a postorder traversal, we recursively do a postorder traversal of the left subtree and the right subtree followed by a visit to the root node.
Suppose that you wanted to read this book from front to back. The preorder traversal gives you exactly that ordering. Starting at the root of the tree (the Book node) we will follow the preorder traversal instructions. We recursively call preorder on the left child, in this case Chapter 1. We again recursively call preorder on the left child to get to Section 1.1. Since Section 1.1 has no children, we do not make any additional recursive calls. When we are finished with Section 1.1, we move up the tree to Chapter 1.
# functiondefpreorder(tree): if tree:print(tree.get_root_val())preorder(tree.get_left_child())preorder(tree.get_right_child())
# functiondefpostorder(tree): if tree !=None:postorder(tree.get_left_child())postorder(tree.get_right_child())print(tree.get_root_val())
# functiondefinorder(tree): if tree !=None:inorder(tree.get_left_child())print(tree.get_root_val())inorder(tree.get_right_child())
Binary Tree and its traversal using python.
Binary tree are the tree where one node can have only two child and cannot have more than two. Traversal means visiting all the nodes of the Binary tree. There are three types of traversal.
Lets take the below tree for example.
Inorder traversal
In order traversal means visiting first left, then root and then right.
So the traversal of above tree would be 4 2 5 1 3
Pre Order Traversal
In this traversal we first visit root, then left, then right
It will be something like this 1 2 4 5 3
Post Order traversal
Here we first visit left, then right and then root.
It will be something like this 4 5 2 3 1
These were the traversal now lets code it in python
So this is how you write the binary tree in Python.
Lets have a look at the script.
We made a class Node which represent the node of Binary tree. We initialize the node with data and left and right child as None.
When we add new child we simple use root.left or root.left.left to add a new child.
Now lets have a look at the traversal functions.
In all these functions we took advantage of recursion and passed the subtrees in the functions again to print in proper order. In Inorder function, we first pass the left subtree to Inorder then print the node and then pass the right subtree. Thus made left, root and right. Similarly we did for the other two.
Here we took a look into how to code binary Tree and its traversal using python.
Algorithms: Mirror a Binary tree using python
Binary tree are the tree where one node can have only two child and cannot have more than two. Traversal means visiting all the nodes of the Binary tree.
Lets take the below tree for example.
So we will be writing python code for changing the tree to its mirror.
Thus you can see the mirror trees inorder traversal. It was really simple we just traversed the tree and changed the right subtree with left and left subtree with right subtree.
Level order traversal of a binary tree.
Level order traversal means that we visit the nodes level by level. Like for below tree the level order traversal will be
Algorithms: Binary Search Tree and its functionality in python
Back in the algorithms section with python we are going to see how we can code Binary Search Tree and its functionality in python. Binary search tree are binary tree where the left child is less than root and right child is greater than root. We will be performing insertion, searching, traversal, min and other functions. Read more about them here.Level order traversal of a binary tree.
Binary Search Tree and its functionality in python
Node class to make the nodes of binary search tree.
Then insert functions, what this function is doing is checking if the data is lesser than node then moves to left child else moves to right child and place it at the end.
Search function again works same as insert functions. The only difference is in this we are getting and telling if the data is present while in insert we are adding node to the true.
In order traversal to visit all the node. Do you know in order traversal of binary search tree is in sorted order.
Get min and Get max functions to get the minimum and maximum of the Binary Search Tree.
Delete I am leaving delete function for you. If you are stuck comment below and I will write a delete function for you.
Currying by default is probably not particularly 'Pythonic', but it does work well with higher-order functions – giving us more flexibility in compositional structure. It also often protects us from over-proliferation of the slightly noisy lambda keyword. (See for example the use of the curried version of map in the code below).
The approach taken here is to focus on the evaluation of expressions, rather than the sequencing of procedures. To keep evaluation simple and easily rearranged, mutation is stripped back wherever possible, and 'pure' functions, with inputs and outputs but, ideally, with no side-effects (and no sensitivities to global variables) are the basic building-block.
Composing pure functions also works well with library-building and code reuse – the literature on functional programming (particularly in the ML / OCaml / Haskell tradition) is rich in reusable abstractions for our toolkit. Some of them have already been absorbed, with standard or adjusted names, into the Python itertools module. (See the itertools module preface, and the takewhile function below).
Here, for example, for the pre-, in- and post- orders, we can define a very general and reusable foldTree (a catamorphism over trees rather than lists) and just pass 3 different (rather simple) sequencing functions to it.
This level of abstraction and reuse brings real efficiencies – the short and easily-written foldTree, for example, doesn't just traverse and list contents in flexible orders - we can pass all kinds of things to it. For the sum of all the numbers in the tree, we could write:
foldTree(lambda x: lambda xs: x + sum(xs))(tree)
and for various other metrics, and the traversal sequences:
'''Tree traversals'''from itertools import (chain, takewhile)from functools import (reduce)from operator import (mul)# foldTree :: (a -> [b] -> b) -> Tree a -> bdeffoldTree(f):'''The catamorphism on trees. A summary value derived by a depth-first fold.'''defgo(node):returnf(root(node))(list(map(go, nest(node))) )returnlambdatree: go(tree)# levels :: Tree a -> [[a]]deflevels(tree):'''A list of the nodes at each level of the tree.''' map_ =curry(map)returnlist(map_(map_(root))(takewhile(bool,iterate(concatMap(nest))( [tree] ) ) ) )# preorder :: a -> [[a]] -> [a]defpreorder(x):'''This node followed by the rest.'''returnlambdaxs: [x] +concat(xs)# inorder :: a -> [[a]] -> [a]definorder(x):'''Descendants of any first child, then this node, then the rest.'''returnlambdaxs: ( xs[0]+ [x] +concat(xs[1:])if xs else [x] )# postorder :: a -> [[a]] -> [a]defpostorder(x):'''Descendants first, then this node.'''returnlambdaxs: concat(xs)+ [x]# levelorder :: Tree a -> [a]deflevelorder(tree):'''Top-down concatenation of this node with the rows below.'''returnconcat(levels(tree))# treeSum :: Tree Int -> IntdeftreeSum(x):'''This node's value + the sum of its descendants.'''returnlambdaxs: x +sum(xs)# treeSum :: Tree Int -> IntdeftreeProduct(x):'''This node's value * the product of its descendants.'''returnlambdaxs: x *numericProduct(xs)# treeMax :: Tree Int -> IntdeftreeMax(x):'''Maximum value of this node and any descendants.'''returnlambdaxs: max([x] + xs)# treeMin :: Tree Int -> IntdeftreeMin(x):'''Minimum value of this node and any descendants.'''returnlambdaxs: min([x] + xs)# nodeCount :: Tree a -> IntdefnodeCount(_):'''One more than the total number of descendants.'''returnlambdaxs: 1+sum(xs)# treeWidth :: Tree a -> IntdeftreeWidth(_):'''Sum of widths of any children, or a minimum of 1.'''returnlambdaxs: sum(xs)if xs else1# treeDepth :: Tree a -> IntdeftreeDepth(_):'''One more than that of the deepest child.'''returnlambdaxs: 1+ (max(xs)if xs else0)# TEST ----------------------------------------------------# main :: IO ()defmain():'''Test'''# tree :: Tree Int tree =Node(1)([Node(2)([Node(4)([Node(7)([]) ]),Node(5)([]) ]),Node(3)([Node(6)([Node(8)([]),Node(9)([]) ]) ]) ])for f in [preorder, inorder, postorder, levelorder, treeSum, treeProduct, treeMin, treeMax, nodeCount, treeWidth, treeDepth]: s = f.__name__print( s.rjust(12, ' ') +':', (foldTree(f) if'levelorder'!= s else f)( tree ) )# GENERIC -------------------------------------------------# Node :: a -> [Tree a] -> Tree adefNode(v):'''Contructor for a Tree node which connects a value of some kind to a list of zero or more child trees.'''returnlambdaxs: {'type':'Node','root': v,'nest': xs}# nest :: Tree a -> [Tree a]defnest(tree):'''Accessor function for children of tree node'''return tree['nest']if'nest'in tree elseNone# root :: Dict -> adefroot(tree):'''Accessor function for data of tree node'''return tree['root']if'root'in tree elseNone# concat :: [[a]] -> [a]# concat :: [String] -> Stringdefconcat(xxs):'''The concatenation of all the elements in a list.''' xs =list(chain.from_iterable(xxs)) unit =''ifisinstance(xs, str)else []return unit ifnot xs else (''.join(xs)ifisinstance(xs[0], str)else xs )# concatMap :: (a -> [b]) -> [a] -> [b]defconcatMap(f):'''Concatenated list over which a function has been mapped. The list monad can be derived by using a function f which wraps its output a in list, (using an empty list to represent computational failure).'''returnlambdaxs: list( chain.from_iterable(map(f, xs) ) )# curry :: ((a, b) -> c) -> a -> b -> cdefcurry(f):'''A curried function derived from an uncurried function.'''returnlambdaa: lambdab: f(a, b)# iterate :: (a -> a) -> a -> Gen [a]defiterate(f):'''An infinite list of repeated applications of f to x.'''defgo(x): v = xwhileTrue:yield v v =f(v)returnlambdax: go(x)# numericProduct :: [Num] -> NumdefnumericProduct(xs):'''The arithmetic product of all numbers in xs.'''returnreduce(mul, xs, 1)if__name__=='__main__':main()