Tree
A tree is a data structure that represents a hierarchical relationship. A link to another node is one way (only from higher to lower, no cyclic connection), and each node has its own subtree.
Component
- Node: an element of a tree (data + link to its child node(s))
- Root node: The top node of a tree
- Parent node (higher) <-> Child node (lower)
- Sibling nodes: Nodes that have the same parent nodes.
- Ancestor node: A parent or higher node
- Descendent node: A child or lower node
- Terminal node (=leaf): A node that doesn’t have a child node
- Internal node: A node that is not a terminal node
- Edge: a line connects two adjacent nodes
Terms
- Level: Depth from the root (level of the root = 1)
- Height (=depth of a tree): The maximum level of a tree
- Degree of a node: Its number of child node(s)
- Degree of a tree: The maximum degree of a node within a tree
Binary tree
A tree whose degree is two or smaller is a binary tree. In a binary tree, every internal node has either one or two children. Every subtree of a binary tree is another binary tree.
N-degree tree can be a binary tree
Every n-degree tree can be transformed into a binary tree by following steps.
- Remove all edges except the connection between a parent and the most left child.
- From every node, draw an edge to its sibling at the right.
- Rotate the tree 90 degrees clockwise.
Variations
- Complete binary tree: All internal nodes have two children nodes
- Perfect/Full binary tree: All level is full (l-th level has 2^l nodes). A perfect binary tree is a complete binary, but not vice versa.
- Skewed binary tree: Every node has either one or zero child.
Traverse
Breadth First Search (BFS)
- Level order traversal: Start from the root, scan all nodes in a level, then move to the next level, and iterate this process.
- Implementation: Queue (children should wait until all of their parent and its sibling(s) is popped out, see the code below)
Depth First Search (DFS)
- Traverse until meeting a leaf, then go back to the previous node, then traverse to another direction, and iterate this process.
- Variation
- Pre-order traversal: Self->Left child->Right child
- In-order traversal: Left child->Self->Right child
- Post-order traversal: Left child->Right child->Self
- Implementation: Recursive algorithm (see the code below) or Stack (The deeper the node, the closer to the top in a stack. Then once the deepest node is searched, it is popped out.)
Implementation
Binary tree implementation can be done using a linked list with two pointers, for its left child and right child.
This representation matches the intuitive image of a tree with its node connections. Array can be used as well, however, not efficient in memory usage except for full trees.
from collections import deque
# can be used as a queue or stack
class Tree:
class Node:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
def traverse_level(self,root_node):
if root_node==None:
return
q = deque()
# first, add root
q.append(root_node)
while q:
current_node = q.pop()
print('Level order - node:',current_node.data)
if current_node.left != None:
q.appendleft(current_node.left)
if current_node.right != None:
q.appendleft(current_node.right)
def traverse_pre(self,root_node):
if root_node:
print('Preorder - node:',root_node.data)
self.traverse_pre(root_node.left)
self.traverse_pre(root_node.right)
else:
return
def traverse_in(self,root_node):
if root_node:
self.traverse_in(root_node.left)
print('Inorder - node:',root_node.data)
self.traverse_in(root_node.right)
else:
return
def traverse_post(self,root_node):
if root_node:
self.traverse_post(root_node.left)
self.traverse_post(root_node.right)
print('Postorder - node:',root_node.data)
else:
return
tt = Tree()
node = tt.Node('Root')
node.left = tt.Node('A')
node.right = tt.Node('B')
node.left.left = tt.Node('C')
node.left.right = tt.Node('D')
node.right.left = tt.Node('E')
node.left.left.left = tt.Node('F')
node.left.left.right = tt.Node('G')
node.left.right.left = tt.Node('H')
tt.traverse_level(node)
tt.traverse_pre(node)
tt.traverse_in(node)
tt.traverse_post(node)
Output:
Level order - node: Root
Level order - node: A
Level order - node: B
Level order - node: C
Level order - node: D
Level order - node: E
Level order - node: F
Level order - node: G
Level order - node: H
Preorder - node: Root
Preorder - node: A
Preorder - node: C
Preorder - node: F
Preorder - node: G
Preorder - node: D
Preorder - node: H
Preorder - node: B
Preorder - node: E
Inorder - node: F
Inorder - node: C
Inorder - node: G
Inorder - node: A
Inorder - node: H
Inorder - node: D
Inorder - node: Root
Inorder - node: E
Inorder - node: B
Postorder - node: F
Postorder - node: G
Postorder - node: C
Postorder - node: H
Postorder - node: D
Postorder - node: A
Postorder - node: E
Postorder - node: B
Postorder - node: Root
Leave a comment