Trees#

Trees are a data structure in which each element can have a descendant that represents an element of the same form.

In python tree can be defined as following class:

import random
from IPython.display import HTML
from copy import deepcopy

class Node:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

Particular realisatoin of the tree example in the cell below:

#    [1]
#  [2] [3]
head = Node(
    1,
    Node(2),
    Node(3)
)

Simple tree visualisation function. Interpretation of the result:

[Head node]
    [Left_1]
        [Left_l2]
        [Right_l2]
    [Right_1]
        [Left_r2]
        [Right_r2]
def print_tree(node, indent=0):
    if node is not None:
        print(f"{indent*' '}[{node.val}]")
        print_tree(node.left, indent+2)
        print_tree(node.right, indent+2)
    else:
        print(f"{indent*' '}[ ]")

head = Node(
    1,
    Node(
        2,
        Node(val=3),
        Node(val=4)
    ),
    Node(
        5,
        Node(val=6),
        Node(val=7)
    )
)
print_tree(head)
[1]
  [2]
    [3]
      [ ]
      [ ]
    [4]
      [ ]
      [ ]
  [5]
    [6]
      [ ]
      [ ]
    [7]
      [ ]
      [ ]

Here is funciton that generates random tree:

def gen_tree(p_left = 0.5, p_right = 0.5):
    '''
    Generate tree:

    Parameters
    ----------
    p_left : (float)
        probability to the node under consideration 
        is added node from the left;
    p_right : (flaot)
        probability to the node udner consideration
        is added node from the right side.
    '''
    return Node(
        val = random.randint(1, 100),
        left = (
            gen_tree(p_left, p_right) 
            if random.random() < p_left else
            None
        ),
        right = (
            gen_tree(p_left, p_right)
            if random.random() < p_right else
            None
        )
    )

random.seed(10)
head = gen_tree(p_left = 0.3, p_right = 0.3)
print_tree(head)
[74]
  [62]
    [ ]
    [63]
      [ ]
      [ ]
  [67]
    [ ]
    [96]
      [ ]
      [18]
        [ ]
        [ ]

Inorder#

Traversal of the tree in order showed in the fllowing cell. “In order” means that the leftmost elements of the tree will always be processed first.

Extracting element#

So here is example that adds elements to a sequential array:

def inorder(root : Node, res):
    if root is not None:
        inorder(root.left, res)
        res.append(root.val)
        inorder(root.right,res)
    return res

And use of the funtion:

head = Node(1, 
    Node(5, Node(7), Node(8)), 
    Node(6, Node(9), Node(10))
)
print_tree(head)
inorder(head, [])
[1]
  [5]
    [7]
      [ ]
      [ ]
    [8]
      [ ]
      [ ]
  [6]
    [9]
      [ ]
      [ ]
    [10]
      [ ]
      [ ]
[7, 5, 8, 1, 9, 6, 10]

Comparison of trees#

Here is algorithm for trees comparison base on inorder.

def are_trees_equal(head1, head2):
    # here is 
    if (head1 is None) != (head2 is None):
        return False
    if (head1 is None):
        return True
    if head1.val != head2.val:
        return False
    return all([
        are_trees_equal(head1.left, head2.left),
        are_trees_equal(head1.right, head2.right)
    ])

In the following cell three trees are created. The first and second are different, but the third is just a copy of the first.

random.seed(10)
tree1 = gen_tree(0.3, 0.3)
display(HTML("<p style='font-size:16px'>Tree 1</p>"))
print_tree(tree1)

tree2 = gen_tree(0.3, 0.3)
display(HTML("<p style='font-size:16px'>Tree 2</p>"))
print_tree(tree2)

tree3 = deepcopy(tree1)
display(HTML("<p style='font-size:16px'>Tree 3</p>"))
print_tree(tree3)

Tree 1

[74]
  [62]
    [ ]
    [63]
      [ ]
      [ ]
  [67]
    [ ]
    [96]
      [ ]
      [18]
        [ ]
        [ ]

Tree 2

[37]
  [ ]
  [23]
    [ ]
    [ ]

Tree 3

[74]
  [62]
    [ ]
    [63]
      [ ]
      [ ]
  [67]
    [ ]
    [96]
      [ ]
      [18]
        [ ]
        [ ]

Here is the result of the application function under consideration.

print(
    "Tree1==Tree2 -", 
    are_trees_equal(tree1, tree2)
)
print(
    "Tree1==Tree3 -",
    are_trees_equal(tree1, tree3)
)
Tree1==Tree2 - False
Tree1==Tree3 - True