trees
TRANSCRIPT
TreesEleonora Ciceri, Politecnico di Milano
Email: [email protected]
Definition: Graph
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
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)
Structure of a social network
from: Wikipedia, the free encyclopedia, Social graph
Some definitionConnected componentsClique
Trees
What is a tree?
Tree: plant characterized by a trunk with branches in the upper part, called foliage
root
leavesbranch
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
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
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
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
Using trees
Video phylogeny: trace a document’s copy process on the Web, e.g., when it is protected by copyright laws
Similarity relationships
Tree components
Tree components
root
leaves
branch
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
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
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
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
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
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
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
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
Binary 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
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
Binary tree: from concept to implementation
We are going to store the tree as a dynamic data structure
Ideas?
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
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:
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
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
Binary tree: Structure
struct TreeNode { int data; TreeNode* leftPtr; TreeNode* rightPtr;};
2
7 8
2 9 3 1
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
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
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
Manual creation of a binary tree
Binary tree: manual creation
1
rootNode
2 3leftChild rightChild
4
leftChild2
5rightChild2
rightChild2->data = 5;rightChild2->leftPtr = NULL;rightChild2->rightPtr = NULL;
Binary tree: manual creation
1
rootNode
2 3leftChild rightChild
4
leftChild2
5rightChild2
rootNode->leftPtr = leftChild;rootNode->rightPtr = rightChild;
Binary tree: manual creation
1
rootNode
2 3leftChild rightChild
4
leftChild2
5rightChild2
leftChild->leftPtr = leftChild2;leftChild->rightPtr = rightChild2;
Counting nodes
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…
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”
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
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
Counting nodes
1+ nodes-left + nodes-right
1+ 1 + nodes-right
1+ 0 + 1
1+ nodes-left + nodes-right
1+ 1 + 2
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
Counting nodes
1+ 4 + nodes-right
1+ 0 + 1
1+ 4 + 2
Node count = 7
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
Counting nodes
Question: while performing the recursive calls, do the pointers to the nodes have to be passed by copy or by reference?
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?
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?
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?”)
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
Computing tree height
Computing tree height
Tree height: length of the longest path between the root and a leaf
Height
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?
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
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
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
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
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
Element search in the tree
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!
Element search in the tree
We will return currentNode if…?
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)
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…?
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
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; }}
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…
Printing tree nodesAKA: how to merge linked lists and binary 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
Printing tree nodes
printPaths(rootNode);1 2 41 2 51 3
1
2 3
4 5
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?
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?
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!
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
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
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
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
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
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
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
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
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}
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);
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}
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}
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}
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}
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}
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}
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}
Additional notes on 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
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)
Exercises
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
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
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);
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
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
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;}
Equal trees
Write a function that, given two trees, returns true if the trees are identical false if the trees are not identical
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
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));}
Tree depth
Write a function that checks whether all the paths have equal length
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;}
Sum of leaf nodes (1)
Write a function that provides the sum of leaf nodes
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);}
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
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));}
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));}
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
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
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); }}
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
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
Ordered tree insertion
For each element…
…we verify its position and insert it as a leaf
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);}
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;}
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
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);}
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
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);}
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);}
Equal sum on trees
bool isEqualLeafSummation(TreeNode* rootNode1, TreeNode* rootNode2) { int sumFirstTree = computeLeafSummation(rootNode1); int sumSecondTree = computeLeafSummation(rootNode2);
return (sumFirstTree == sumSecondTree) || isLeafEqualToNumber(rootNode1, sumSecondTree);
}
The mirror
Change a tree in its mirrored version
1
2 3
4 5
1
23
45
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?
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
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;}
}
References
References
Alberi: http://it.wikipedia.org/wiki/Albero_(informatica) http://www.di.unisa.it/~demarco/sd/lezioni/
lezione11.pdf