trees

131
Trees Eleonora Ciceri, Politecnico di Milano Email: [email protected]

Upload: eleonora-ciceri

Post on 13-Feb-2017

237 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Trees

TreesEleonora Ciceri, Politecnico di Milano

Email: [email protected]

Page 2: Trees

Definition: Graph

Page 3: Trees

Graph

Graph: set of elements (nodes) connected with lines (edges) G = (V,E) V: set of nodes E: set of edges such that an element in E connects a pair

of elements in V

V = (1,2,3,4,5)E = (a,b,c,d)

1

2

3

4

5

a

bc

d

Page 4: Trees

Graph

Graph types Directed graph: graph in which edges are characterized by

a direction(from node A to node B) Undirected graph: graph which does not contain directed

edges; if an edge is drawn from node A to node B, it means that we can move both from A to B and from B to A

Famous examples of graphs Social networks (nodes: users; edges: friendship) Computer networks (nodes: computers; edges: physical

connections) Transportation networks(nodes: cities; edges: routes)

Page 5: Trees

Structure of a social network

from: Wikipedia, the free encyclopedia, Social graph

Some definitionConnected componentsClique

Page 6: Trees

Trees

Page 7: Trees

What is a tree?

Tree: plant characterized by a trunk with branches in the upper part, called foliage

root

leavesbranch

Page 8: Trees

What is a tree?

Tree: undirected graph in which two nodes are connected by one and only one path Node: contains

some data Edge: specifies a

hierarchical connection between nodes

root

leaves

branch

Page 9: Trees

What is a tree?

Tree: undirected graph in which two nodes are connected by one and only one path Node: contains

some data Edge: specifies a

hierarchical connection between nodes

root

leaves

branchpath

Page 10: Trees

What is a tree?

Tree: undirected graph in which two nodes are connected by one and only one path Node: contains

some data Edge: specifies a

hierarchical connection between nodes

root

leaves

branchpath

A tree is acyclicThere does not exist any alternative path to go from node A to node B

Page 11: Trees

Using trees

When do you use trees? To represent hierarchical data To rapidly look for objects To represent decision flows To represent object orderings

Question 1

Answer A Answer B

Question 2 Question 3

Decision tree Tree of possible orderings

Page 12: Trees

Using trees

Video phylogeny: trace a document’s copy process on the Web, e.g., when it is protected by copyright laws

Similarity relationships

Page 13: Trees

Tree components

Page 14: Trees

Tree components

root

leaves

branch

Page 15: Trees

Tree components:Root node

It is strictly required that a tree contains a unique node which does not have incoming edges This node is called root node

There does not exist a tree without a root node

Page 16: Trees

Tree components:Leaf node

Every node which does not have outgoing edges is called leaf node

Every finite tree (i.e., which contains a finite number of nodes) there exists at least a leaf node

Page 17: Trees

Tree components:Edges

An edge (or: branch) defines a hierarchical connection between nodes

A parent node is a node with an outgoing edgei.e., the parent node is higher

than a child node

Page 18: Trees

Tree components:Edges

A child node is a node with an incoming edgei.e., a child node is lower than

its parent node

An edge (or: branch) defines a hierarchical connection between nodes

Page 19: Trees

Tree components:Nodes and edges

A node can be a parent node and a child node at the same time, and this happens if it has both incoming edges and outgoing edges

In this case the node is called internal node An internal node is not a leaf node

RootParent of

Parent ofChild of Root

Father ofChild of

LeafChild of

The root does not have a parent

A leaf does not have children

Page 20: Trees

Balanced and unbalanced trees

The leaves could be positioned at different levels; their positioning defines the tree balancing property If leaves are position “closely” (e.g., at maximum a single

level separates them) then the tree is balanced

Tree (perfectly) balanced Unbalanced tree

Page 21: Trees

Definitions

Node height: length of the longest path between the node and a leaf

Node depth: length of path from the node and the tree root

Height

Depth

Page 22: Trees

Definitions

Sub-tree of a tree T: tree consisting in a node n belonging to tree T, together with all its descendants in T

The sub-tree corresponding to the root T is the whole tree T

Page 23: Trees

Binary trees

Page 24: Trees

Binary tree vs. N-ary tree

A binary tree is a tree whose nodes can have two children at maximum

An n-ary tree is a tree where there does not exist a limit on the number of children a node could have

Page 25: Trees

Binary complete trees vs. Binary incomplete trees

A tree is complete if it is a binary tree and: Each level (except the last) is full of nodes The nodes are at the leftmost positions

The last level may contain few nodes, but it has to be filled from left to right

Complete tree Incomplete tree

Page 26: Trees

Binary tree: from concept to implementation

We are going to store the tree as a dynamic data structure

Ideas?

Page 27: Trees

Binary tree: from concept to implementation

We are going to store the tree as a dynamic data structure

How to position them?

Ingredients

What to represent

StructPointers

NodesEdges

Page 28: Trees

Binary tree: from concept to implementation

struct structstruct

struct struct

Ingredients

What to represent

StructPointers

NodesEdges

We are going to store the tree as a dynamic data structure

We’ll use the same principles used with linked lists:

Page 29: Trees

Binary tree: Structure

Each node in a binary tree contains: A left pointer A right pointer Data

The pointers in the node point recursively at two sub-trees (i.e., smaller trees) positioned on its left side and right side

Left Sub-tree

RightSub-tree

LeftSub-tree

RightSub-Tree

Page 30: Trees

Binary tree: Structure

We’ll see then a node as follows:

Note. Since the node structure is dynamic, we have to be very careful in handling the pointer to the root: if we lose it, we lose every possibility of accessing to the tree!

Data contained in the node

Left sub-tree Right sub-tree

Page 31: Trees

Binary tree: Structure

struct TreeNode { int data; TreeNode* leftPtr; TreeNode* rightPtr;};

2

7 8

2 9 3 1

Page 32: Trees

Binary tree: Structure

struct TreeNode { int data; TreeNode* leftPtr; TreeNode* rightPtr;};

2

7 8

2 9 3 1

The root is pointed to by a “head” pointer

Page 33: Trees

Binary tree: Structure

struct TreeNode { int data; TreeNode* leftPtr; TreeNode* rightPtr;};

2

7 8

2 9 3 1

Leaves have left and right pointers set to null

Page 34: Trees

Incomplete binary tree

Internal nodes do not have necessarily both left and right children, some of them may be null

2

7 8

9 3

2

7 8

3 1

Page 35: Trees

Manual creation of a binary tree

Page 36: Trees

Binary tree: manual creation

1

rootNode

2 3leftChild rightChild

4

leftChild2

5rightChild2

rightChild2->data = 5;rightChild2->leftPtr = NULL;rightChild2->rightPtr = NULL;

Page 37: Trees

Binary tree: manual creation

1

rootNode

2 3leftChild rightChild

4

leftChild2

5rightChild2

rootNode->leftPtr = leftChild;rootNode->rightPtr = rightChild;

Page 38: Trees

Binary tree: manual creation

1

rootNode

2 3leftChild rightChild

4

leftChild2

5rightChild2

leftChild->leftPtr = leftChild2;leftChild->rightPtr = rightChild2;

Page 39: Trees

Counting nodes

Page 40: Trees

Counting nodes

Aim: counting the number of nodes in the tree The approach we propose for any algorithm involving

tree manipulation is recursive. Thus, it is necessary to define: A base case A recursion step

Hint: always look for base case in the leaves of the tree…

Page 41: Trees

Counting nodes

1+ nodes-left + nodes-right

1+ nodes-left + nodes-right

1+ nodes-left + nodes-rightTo visit the child nodes of n, we visit first its left sub-

tree and then its right sub-tree

Given a node n, we count the number of nodes in the sub-tree

having n as root as:1 + “the number of child nodes on the left” + “the number of child nodes on the right”

Page 42: Trees

Counting nodes

1+ nodes-left + nodes-right

1+ nodes-left + nodes-right

1+ nodes-left + nodes-right =

0

=

0

1+ nodes-left + nodes-right

1+ 1 + nodes-right

When we reach a leaf, we go back to its parent node If we were visiting the left sub-

tree, we move to the right sub-tree

Page 43: Trees

Counting nodes

1+ nodes-left + nodes-right

1+ 1 + nodes-right

1+ nodes-left + nodes-right

=

0

1+ nodes-left + nodes-right

1+ 1 + nodes-right

1+ 0 + nodes-right

=

0

1+ nodes-left + nodes-right =

0

Page 44: Trees

Counting nodes

1+ nodes-left + nodes-right

1+ 1 + nodes-right

1+ 0 + 1

1+ nodes-left + nodes-right

1+ 1 + 2

Page 45: Trees

Counting nodes

1+ 4 + nodes-right

1+ 4 + nodes-right

1+ nodes-left + nodes-right

1+ 4 + nodes-right

1+ 0+ nodes-right

1+ nodes-left + nodes-right

=

0

=

0

=

0

Page 46: Trees

Counting nodes

1+ 4 + nodes-right

1+ 0 + 1

1+ 4 + 2

Node count = 7

Page 47: Trees

Counting nodes

The proposed procedure is, again, recursive

When we reach a node (any node): We add +1 to count the current node We ask to count nodes in the left sub-tree We ask to count nodes in the right sub-tree

The base case is on a null pointer (i.e., a “missing” left sub-tree or right sub-tree). It is NOT a node: It does not have left children It does not have right children Its contribution to the total count is 0

Page 48: Trees

Counting nodes

Question: while performing the recursive calls, do the pointers to the nodes have to be passed by copy or by reference?

Page 49: Trees

Counting nodes

Question: while performing the recursive calls, do the pointers to the nodes have to be passed by copy or by reference? Do I have to propagate any updates to the pointer when I return from the recursive call execution?

Page 50: Trees

Counting nodes

Question: while performing the recursive calls, do the pointers to the nodes have to be passed by copy or by reference? Do I have to propagate any updates to the pointer when I return from the recursive call execution?Do I need to change the tree structure?

Page 51: Trees

Counting nodes

Answer: counting nodes does not have to change the tree structure If I passed any pointer by reference, and it was modified

by the function, it would update the pointer in the caller, changing the structure of the tree (“where is the root of the tree now?”)

Page 52: Trees

Counting nodes

int countNodes(TreeNode* currentNode) { if (currentNode == NULL) return 0; else return 1 + countNodes(currentNode->leftPtr)

+ countNodes(currentNode->rightPtr);}

Pointer to the current node

Base case

Recursive step

Page 53: Trees

Computing tree height

Page 54: Trees

Computing tree height

Tree height: length of the longest path between the root and a leaf

Height

Page 55: Trees

Computing tree height

The common trick to write correctly tree manipulation functions is to understand which are the base case and the recursion step

The base case is usually set on the leaves of the tree Which is the right approach to compute tree height?

Page 56: Trees

Computing tree height

The common trick to write correctly tree manipulation functions is to understand which are the base case and the recursion step

The base case is usually set on the leaves of the tree Which is the right approach to compute tree height?

Base case: if the current pointer is NULL, it means we are at the “end” (lower end) of the tree. Thus, the current height is 0 (we are at the base of the tree)

Height

Page 57: Trees

Computing tree height

The common trick to write correctly tree manipulation functions is to understand which are the base case and the recursion step

The base case is usually set on the leaves of the tree Which is the right approach to compute tree height?

Base case: if the current pointer is NULL, it means we are at the “end” (lower end) of the tree. Thus, the current height is 0 (we are at the base of the tree)

Generic case: if the current pointer is NULL, the current node’s height is 1 + the height of its chidren

Height

Page 58: Trees

Computing tree height

BaseHeight with respect to the base: 0

Height (with respect to the base): 1

Height (with respect to the base): 2

Height (with respect to the base): 3

Page 59: Trees

Computing tree height

My child’s height: 0My height: 1+0 = 1

My child’s height: 1My height: 1+1 = 2

My left child’s height: 1My right child’s height: 2My height: 1+max(1,2) = 3

BaseHeight with respect to the base: 0

Height (with respect to the base): 1

Height (with respect to the base): 2

Height (with respect to the base): 3

Page 60: Trees

Computing tree height

int computeTreeHeight(TreeNode* currentNode) { if (currentNode == NULL) return 0; else return 1 + std::max(computeTreeHeight(currentNode->leftPtr), computeTreeHeight(currentNode->rightPtr));}

Height of sub-tree having root leftPtr

Height of sub-tree having root rightPtr

Page 61: Trees

Element search in the tree

Page 62: Trees

Element search in the tree

Element search returns: NULL if the element is not in the tree A pointer to the node that contains the element, if the

element is in the tree

The tree is not ordered. Thus, given a node, the element that we are looking for could be: The current node A node in the left sub-tree A node in the right sub-tree …not present, too!

Page 63: Trees

Element search in the tree

We will return currentNode if…?

Page 64: Trees

Element search in the tree

We will return currentNode if: currentNode is NULL (i.e., we got to the end of the tree

and we did not find anything along the path we followed) currentNode contains the element (i.e., the search is

done)

Page 65: Trees

Element search in the tree

We will return currentNode if: currentNode is NULL (i.e., we got to the end of the tree

and we did not find anything along the path we followed) currentNode contains the element (i.e., the search is

done)

In case currentNode is not NULL and not containing the element we want to find…?

Page 66: Trees

Element search in the tree

We will return currentNode if: currentNode is NULL (i.e., we got to the end of the tree and

we did not find anything along the path we followed) currentNode contains the element (i.e., the search is

done)

In case currentNode is not NULL and not containing the element we want to find: We look for the element in the left sub-tree. If the element

is here, I’ll return it If the element is NOT in the left sub-tree, I’ll return the result

of the search in the right sub-tree Either the element, if present, or NULL

Page 67: Trees

Element search in the tree

TreeNode* findNode(TreeNode* currentNode, int element) { if (currentNode == NULL || currentNode->data == element) return currentNode; else { TreeNode* leftSearchResult = findNode(currentNode->leftPtr, element); TreeNode* rightSearchResult = findNode(currentNode->rightPtr, element); if (leftSearchResult != NULL) return leftSearchResult; else return rightSearchResult; }}

Page 68: Trees

Element search in the tree

TreeNode* findNode(TreeNode* currentNode, int element) { if (currentNode == NULL || currentNode->data == element) return currentNode; else { TreeNode* leftSearchResult = findNode(currentNode->leftPtr, element); if (leftSearchResult != NULL) return leftSearchResult; else return findNode(currentNode->rightPtr, element); }}

Equivalently…

Page 69: Trees

Printing tree nodesAKA: how to merge linked lists and binary trees

Page 70: Trees

Printing tree nodes

Paths in the tree may have different lengths Approach:

navigate the tree first at the left side, then at the right side store each path in a linked list when we reach a leaf, the path is as its end, thus we can print it

(i.e., we print the content of the linked list)

1

2 3

4 5

Page 71: Trees

Printing tree nodes

printPaths(rootNode);1 2 41 2 51 3

1

2 3

4 5

Page 72: Trees

Printing tree nodes

How do we print paths?

That is: How do we navigate through the tree so as to visit every

path, one after another? How to store a path in a linked list?

Page 73: Trees

Printing tree nodes

How do we navigate through the tree so as to visit every path, one after another? We visit the tree by traversing the left sub-trees first and the

right sub-trees after This is similar to what happened with the nodes printing

procedure

How to store a path in a linked list? At first, we initialize the list as an empty list As we visit nodes along a path, we attach those nodes in the

list On the head? On the tail?

Page 74: Trees

Printing tree nodes

How do we navigate through the tree so as to visit every path, one after another? We visit the tree by traversing the left sub-trees first and the

right sub-trees after This is similar to what happened with the nodes printing

procedure

How to store a path in a linked list? At first, we initialize the list as an empty list As we visit nodes along a path, we attach those nodes in the list

On the tail, otherwise we will print the path in the wrong direction!

Page 75: Trees

Printing tree nodes: initializing the linked list

In printPaths(): We initialize the list head We initialize the list tail We start the tree printing procedure

void printPaths(TreeNode* rootNode) { ListNode* pathHead = NULL; ListNode* pathTail = NULL; printPaths(rootNode, pathHead, pathTail);}

1

2 3

4 5

rootNode

pathHead

pathTail

overload

Page 76: Trees

Printing tree nodes

1

2 3

4 5

rootNode

At first we print this path… 1

2 3

4 5

rootNode

…then this one.

1

2 3

4 5

rootNode

We go to the left sub-tree…

1

2 3

4 5

rootNode

…and again to the left sub-tree. We are at a leaf: we print the list

Page 77: Trees

Printing tree nodes

1

2 3

4 5

rootNode

1

2 3

4 5

rootNode

1

2 3

4 5

rootNode To print this path we go back to the root…

1

2 3

4 5

rootNode

…and we go to the right child. We are at a leaf: we can print the list.

We go back to the parent…

…and then to the right child. We are at a leaf: we print the list

Page 78: Trees

Printing tree nodes We insert the root in the list: 1 We require to print the left child

We insert the left child in the list: 1 2 We require to print the left child

We insert the left child in the list: 1 2 4 We are at a leaf: we print the list We remove the leaf node from the list: 1 2

We require to print the right child We insert the right child in the list: 1 2 5 We are at a leaf: we print the list We remove the leaf node from the list: 1 2

We remove the left child from the list: 1 We require to print the right child

We insert the right child in the list: 1 3 We are at a leaf: we print the list We remove the leaf node from the list: 1

We remove the root from the list:

12 3

4 5

Page 79: Trees

We insert the root in the list: 1 We require to print the left child

We insert the left child in the list: 1 2 We require to print the left child

We insert the left child in the list: 1 2 4 We are at a leaf: we print the list We remove the leaf node from the list: 1 2

We require to print the right child We insert the right child in the list: 1 2 5 We are at a leaf: we print the list We remove the leaf node from the list: 1 2

We remove the left child from the list: 1 We require to print the right child

We insert the right child in the list: 1 3 We are at a leaf: we print the list We remove the leaf node from the list: 1

We remove the root from the list:

Printing tree nodes

First level

12 3

4 5

Page 80: Trees

We insert the root in the list: 1 We require to print the left child

We insert the left child in the list: 1 2 We require to print the left child

We insert the left child in the list: 1 2 4 We are at a leaf: we print the list We remove the leaf node from the list: 1 2

We require to print the right child We insert the right child in the list: 1 2 5 We are at a leaf: we print the list We remove the leaf node from the list: 1 2

We remove the left child from the list: 1 We require to print the right child

We insert the right child in the list: 1 3 We are at a leaf: we print the list We remove the leaf node from the list: 1

We remove the root from the list:

Printing tree nodes

Second level

12 3

4 5

Page 81: Trees

We insert the root in the list: 1 We require to print the left child

We insert the left child in the list: 1 2 We require to print the left child

We insert the left child in the list: 1 2 4 We are at a leaf: we print the list We remove the leaf node from the list: 1 2

We require to print the right child We insert the right child in the list: 1 2 5 We are at a leaf: we print the list We remove the leaf node from the list: 1 2

We remove the left child from the list: 1 We require to print the right child

We insert the right child in the list: 1 3 We are at a leaf: we print the list We remove the leaf node from the list: 1

We remove the root from the list:

Printing tree nodes

Base case: leaf node

12 3

4 5

Page 82: Trees

Printing tree nodes

The procedure is recursive

When we reach a node We add its content to the list We ask to print the left tree We ask to print the right tree We remove its content from the list

Base case: on the leaf We insert its content in the list We ask to print the path from the root to that leaf We remove its content from the list

Page 83: Trees

Printing tree nodesvoid printPaths(TreeNode* rootNode, ListNode* pathHead, ListNode* pathTail) { We insert the node content in the list

We visit the lower level

We remove the node content from the list}

Page 84: Trees

void printPaths(TreeNode* rootNode, ListNode* pathHead, ListNode* pathTail) { We insert the node content in the list

We visit the lower level

We remove the node content from the list}

Printing tree nodes

First case: empty listI have to add the root to the list pathHead = NULL pathTail = NULL

datanewNode

ListNode *oldPathTail = pathTail;addNodeToList(rootNode->data, pathHead, pathTail);

Page 85: Trees

Printing tree nodes

datanewNode

pathHead

pathTail

ListNode *oldPathTail = pathTail;addNodeToList(rootNode->data, pathHead, pathTail);

First case: empty listI have to add the root to the list pathHead = NULL pathTail = NULL

void printPaths(TreeNode* rootNode, ListNode* pathHead, ListNode* pathTail) { We insert the node content in the list

We visit the lower level

We remove the node content from the list}

Page 86: Trees

Printing tree nodes

Second case: non-empty listWe add either a leaf node or an internal node to the list

datanewNode

ApathHead

B

pathTail

ListNode *oldPathTail = pathTail;addNodeToList(rootNode->data, pathHead, pathTail);

void printPaths(TreeNode* rootNode, ListNode* pathHead, ListNode* pathTail) { We insert the node content in the list

We visit the lower level

We remove the node content from the list}

Page 87: Trees

Printing tree nodes

datanewNode

ApathHead

B

pathTail

ListNode *oldPathTail = pathTail;addNodeToList(rootNode->data, pathHead, pathTail);

Second case: non-empty listWe add either a leaf node or an internal node to the list

void printPaths(TreeNode* rootNode, ListNode* pathHead, ListNode* pathTail) { We insert the node content in the list

We visit the lower level

We remove the node content from the list}

Page 88: Trees

Printing tree nodes

id (rootNode->leftPtr == NULL && rootNode->rightPtr == NULL) printPath(pathHead);else { if (rootNod->leftPtr != NULL) printPaths(rootNode->leftPtr, pathHead, pathTail); if (rootNod->rightPtr != NULL) printPaths(rootNode->rightPtr, pathHead, pathTail);}

void printPaths(TreeNode* rootNode, ListNode* pathHead, ListNode* pathTail) { We insert the node content in the list

We visit the lower level

We remove the node content from the list}

Page 89: Trees

Printing tree nodes

if (rootNode->leftPtr == NULL && rootNode->rightPtr == NULL) printPath(pathHead);else { printPaths(rootNode->leftPtr, pathHead, pathTail); printPaths(rootNode->rightPtr, pathHead, pathTail);}

Base case: leaf

void printPaths(TreeNode* rootNode, ListNode* pathHead, ListNode* pathTail) { We insert the node content in the list

We visit the lower level

We remove the node content from the list}

Page 90: Trees

if (rootNode->leftPtr == NULL && rootNode->rightPtr == NULL) printPath(pathHead);else { printPaths(rootNode->leftPtr, pathHead, pathTail); printPaths(rootNode->rightPtr, pathHead, pathTail);}

Printing tree nodes

Generic case: either internal nodes or root node

void printPaths(TreeNode* rootNode, ListNode* pathHead, ListNode* pathTail) { We insert the node content in the list

We visit the lower level

We remove the node content from the list}

Page 91: Trees

Printing tree nodes

If (oldPathTail != NULL) { oldPathTail->next = NULL;}delete pathTail;pathTail = NULL;

void printPaths(TreeNode* rootNode, ListNode* pathHead, ListNode* pathTail) { We insert the node content in the list

We visit the lower level

We remove the node content from the list}

Page 92: Trees

Additional notes on trees

Page 93: Trees

Graph

A graph is a set of nodes connected via edges

It is usually represented as G(V,E), where: V is the set of nodes E is the set of edges

Trees vs. graphs A tree has a unique root, while the graph could have multiple roots Tree nodes have just an incoming edge, while graph edges could

have multiple incoming edges

Page 94: Trees

N-ary trees

Generalization of binary trees Every node could have an arbitrary number of children

It is generally used to represent hierarchical structures (e.g., company employees hierarchy)

Page 95: Trees

Exercises

Page 96: Trees

Counting leaf and non-leaf nodes

Write: A function that counts the number of leaf nodes A function that counts the number of non-leaf nodes

Page 97: Trees

Counting leaf and non-leaf nodes

A leaf node is a node without children leftPtr is NULL rightPtr is NULL

The non-leaf nodes (called internal nodes) are… all the other nodes!

non_leaf_nodes = total_nodes – leaf_nodes

Page 98: Trees

Counting leaf and non-leaf nodes

int countLeaves(TreeNode* currentNode) { if (currentNode == NULL) return 0; if (currentNode->leftPtr == NULL && currentNode->rightPtr == NULL) return 1; return countLeaves(currentNode->leftPtr) + countLeaves(currentNode->rightPtr);}

int leafNumber = countLeaves(rootNode);int nonLeafNumber = countNodes(rootNode) - countLeaves(rootNode);

Page 99: Trees

Counting nodes on even levels

Write a function that counts the number of nodes on even levels of the tree Even levels are the ones having even ID

Level 1

Level 2

Level 3

Level 4

Page 100: Trees

Counting nodes on even levels

We keep track of the current depth with an integer depth = 1 is we are on the root depth = 2 if we are on the root’s children …

If dividing depth by 2 has null reminder, then we add 1 to the count of nodes on even levels

Page 101: Trees

Counting nodes on even levels

int countNodesAtEvenLevels(TreeNode* currentNode, int depth) { if (currentNode == NULL) return 0; int numNodesAtEvenLevels = countNodesAtEvenLevels(currentNode->leftPtr, depth+1) + countNodesAtEvenLevels(currentNode->rightPtr, depth+1); if (depth % 2 == 0) return numNodesAtEvenLevels+1; else return numNodesAtEvenLevels;}

Page 102: Trees

Equal trees

Write a function that, given two trees, returns true if the trees are identical false if the trees are not identical

Page 103: Trees

Equal trees

Given a node n and a node m, the sub-trees having n and m as root are identical if: n and m contain the same value The sub-trees having n->leftPtr and m->leftPtr as root

are identical The sub-trees having n->rightPtr and m->rightPtr as

root are identical

Page 104: Trees

Equal trees

bool isEqual(TreeNode* currentNode1, TreeNode* currentNode2) { if (currentNode1 == currentNode2) return 1; if (currentNode1 == NULL || currentNode2 == NULL) return 0; return (currentNode1-> data == currentNode2 -> data && isEqual(currentNode1->leftPtr, currentNode2->leftPtr) && isEqual(currentNode1->rightPtr, currentNode2->rightPtr));}

Page 105: Trees

Tree depth

Write a function that checks whether all the paths have equal length

Page 106: Trees

Tree depth

int checkDepth(TreeNode* currentNode) { if (currentNode == 0) return 0;

int leftDepth = checkDepth(currentNode->leftPtr); int rightDepth = checkDepth(currentNode->rightPtr);

if (leftDepth == -1 || rightDepth == -1) // error bubbling return -1; if (leftDepth != 0 && rightDepth != 0 && leftDepth != rightDepth) return -1; return std::max(leftDepth, rightDepth) + 1;}

Page 107: Trees

Sum of leaf nodes (1)

Write a function that provides the sum of leaf nodes

Page 108: Trees

Sum of leaf nodes (1)

int computeNodeSum(TreeNode* currentNode) { if (currentNode == NULL) return 0; if (currentNode->leftPtr == NULL && currentNode->rightPtr == NULL) return currentNode->data; return computeNodeSum(currentNode->leftPtr) + computeNodeSum(currentNode->rightPtr);}

Page 109: Trees

Sum of leaf nodes (2)

Assume that every path is associated with a score, which can be computed by summing the node values along that path. Thus, if the tree contains N paths, it contains N scores too (one for each path)

Write a function that returns the highest score

Page 110: Trees

Sum of leaf nodes (2)

int computeMaxPath(TreeNode* currentNode){ if (currentNode == NULL) return 0; if (currentNode->leftPtr == NULL && currentNode->rightPtr == NULL) return currentNode->data; else return std::max(currentNode-> data +

computeMaxPath(currentNode->leftPtr), currentNode->data +

computeMaxPath(currentNode->rightPtr));}

Page 111: Trees

Sum of leaf nodes(2) (alternative solution)

int computeMaxPath(TreeNode* currentNode){ if (currentNode == NULL) return 0; else return currentNode-> data + std::max(computeMaxPath(currentNode->leftPtr),

computeMaxPath(currentNode->rightPtr));}

Page 112: Trees

Serialize leaves

Write a function that extracts all the leaves from the tree and builds a linked list, in which each node represents one of the leaves of the tree

Page 113: Trees

Serialize leaves

We go down at the left

We go back and go down at the right

We go back and go down at the right

Page 114: Trees

Serialize leaves

void saveLeavesInList(TreeNode* currentNode, ListNode*& head) { if (currentNode == NULL) return; else if (currentNode->leftPtr == NULL && currentNode->rightPtr == NULL) { ListNode* newLeaf = new ListNode; newLeaf->data = currentNode->data; newLeaf->nextPtr = head; head = newLeaf; } else { saveLeavesInList(currentNode->leftPtr, head); saveLeavesInList(currentNode->rightPtr, head); }}

Page 115: Trees

Ordered tree insertion

Write a function that, given a vector<string> as an input,inserts the words in a tree in an ordered manner: for every node n in the tree, every word in the left sub-tree come before the word in n alphabetically, while all the others are in the right sub-tree

dogcat horse

alpaca

beeVector: dog, cat, horse, alpaca, bee, shark, fox, mosquito, sheep

shark

mosquito sheep

fox

Page 116: Trees

Ordered tree insertion

For each word from the vector: If it precedes the word contained in the current node, it

has to go down in the left sub-tree If it follows the word contained in the current node, it has

to go down in the right sub-tree

dogcat < dog

dogcat

horse > dog

dogcat horse

alpaca < dogalpaca < cat

dogcat horse

alpaca

Page 117: Trees

Ordered tree insertion

For each element…

…we verify its position and insert it as a leaf

Page 118: Trees

Ordered tree insertionTreeStringNode* saveDictionaryInTree(std::vector<std::string> dictionary) { TreeStringNode* rootNode = NULL;

for (size_t i = 0; i < dictionary.size(); i++) saveWordInTree(rootNode, dictionary.at(i));

return rootNode;}

void saveWordInTree(TreeStringNode* &rootNode, std::string word) { if (rootNode == NULL) rootNode = createNewNode(word); else if (rootNode->data >= word) saveWordInTree(rootNode->leftPtr,word); else saveWordInTree(rootNode->rightPtr, word);}

Page 119: Trees

void saveWordInTree(TreeStringNode* &rootNode, std::string word) { if (rootNode == NULL) rootNode = createNewNode(word); else if (rootNode->data >= word) saveWordInTree(rootNode->leftPtr,word); else saveWordInTree(rootNode->rightPtr, word);}

Ordered tree insertion

TreeStringNode* createNewNode(std::string word) { TreeStringNode* newNode = new TreeStringNode; newNode->data = word; newNode->leftPtr = NULL; newNode->rightPtr = NULL;

return newNode;}

TreeStringNode* saveDictionaryInTree(std::vector<std::string> dictionary) { TreeStringNode* rootNode = NULL;

for (size_t i = 0; i < dictionary.size(); i++) saveWordInTree(rootNode, dictionary.at(i));

return rootNode;}

Page 120: Trees

Even or odd levels?

Write a function that returns true if every number contained in the even levels are even and every number in the odd levels are odd, or false otherwise

Page 121: Trees

Even or odd levels?

bool checkOddEvenNumbers(TreeNode* currentNode, int depth) { if (currentNode == NULL) return 1; if ((currentNode->data % 2) != (depth % 2)) return 0;

return checkOddEvenNumbers(currentNode->leftPtr,depth+1) && checkOddEvenNumbers(currentNode->rightPtr,depth+1);}

Page 122: Trees

Equal sum on trees

Write a function that, given two binary trees, returns true if: The sum of the leaves of the two trees is equal

OR The first tree has at least a leaf whose value is equal to

the sum of the values in the leaves of the second tree

or false otherwise

Page 123: Trees

Equal sum on trees

int computeLeafSummation(TreeNode* currentNode) { if (currentNode == NULL) return 0; else if (currentNode->leftPtr == NULL && currentNode->rightPtr == NULL) return currentNode->data; return computeLeafSummation(currentNode->leftPtr) +

computeLeafSummation(currentNode->rightPtr);}

Page 124: Trees

Equal sum on trees

bool isLeafEqualToNumber(TreeNode* currentNode, int number) { if (currentNode == NULL) return false; else if (currentNode->leftPtr == NULL && currentNode->rightPtr == NULL

&& currentNode->data == number) return true; return isLeafEqualToNumber(currentNode->leftPtr,number) ||

isLeafEqualToNumber(currentNode->rightPtr,number);}

Page 125: Trees

Equal sum on trees

bool isEqualLeafSummation(TreeNode* rootNode1, TreeNode* rootNode2) { int sumFirstTree = computeLeafSummation(rootNode1); int sumSecondTree = computeLeafSummation(rootNode2);

return (sumFirstTree == sumSecondTree) || isLeafEqualToNumber(rootNode1, sumSecondTree);

}

Page 126: Trees

The mirror

Change a tree in its mirrored version

1

2 3

4 5

1

23

45

Page 127: Trees

The mirror

Mirroring the tree means that: What is on the left has to go on the right What is on the right has to go on the left

We are building a new tree, thus every time we return the pointer to the new node

Behavior: What to do when the pointer is NULL? What to do on the nodes?

Page 128: Trees

The mirror

Mirroring the tree means that: What is on the left has to go on the right What is on the right has to go on the left

We are building a new tree, thus every time we return the pointer to the new node

Behavior: When the pointer is NULL: we return NULL (nothing has to

be created) On the nodes: we return the current node and its sub-trees,

which are swapped

Page 129: Trees

The mirror

TreeNode* mirrorTree(TreeNode* currentNode) {if (currentNode == NULL)

return NULL;else {

TreeNode* newMirroredNode = new TreeNode;newMirroredNode->data = currentNode->data;newMirroredNode->leftPtr = mirrorTree(currentNode-

>rightPtr);newMirroredNode->rightPtr = mirrorTree(currentNode-

>leftPtr);

return newMirroredNode;}

}

Page 130: Trees

References

Page 131: Trees

References

Alberi: http://it.wikipedia.org/wiki/Albero_(informatica) http://www.di.unisa.it/~demarco/sd/lezioni/

lezione11.pdf