Transcript Chapter 05

Chapter 05
Trees (Part II)
Array Representation
• We can use an array to represent a complete
binary tree.
• Lemma 5.4
▫ If a complete binary tree with n nodes in given,
then for any node with index i, 1≦i≦n,
 Parent(i) is at  i 2  if i > 1. If i=1, node i is the root.
 LeftChild(i) is at 2i if 2i≦n.
 If 2i > n, node i has no left child.
 RightChild(i) is at 2i+1 if 2i+1≦n.
 If 2i+1 > n, node i has no right child.
Example
0
1
2
C
5
D
8
H
9
E
2
3
4
5
6
7
8 9 10 11
A B C D E F G H I
A
B
4
1
7
6
F
I
Complete binary tree
▫ Node 1:
3
G
 Parent(1): 0, indicating node 1 is
the root.
 LeftChild(1): 2i = 2.
 RightChild(2): 2i+1 = 3.
▫ Node 5:
 Parent(5):
 LeftChild(5):
 RightChild(5):
▫ Node 4:
 Parent(4):
 LeftChile(4):
 RightChild(4):
Array Representation
• Advantages:
▫ Suppose n is the number of nodes. The search
time can be bounded to O(log2n).
• Disadvantages:
▫ The utilization of memory space is not flexible
enough.
Linked Representation
class TreeNode
{
friend class Tree;
private:
int data;
TreeNode *leftChild;
TreeNode *rightChild;
};
class Tree
{
public:
//Tree operations
private:
TreeNode *root;
};
leftChild
data
rightChild
data
leftChild
rightChild
Introduction
• Goal: to visit each node in a tree.
▫ In each node, 6 possible ways can be used to move
forwarding:
▫ LVR, LRV, VLR, VRL, RVL, and RLV.
 L: moving left.
 V: visiting the node.
 R: moving right.
▫ Different traversal approaches result in different
order of output.
Introduction
• Conventionally, we traverse left before right.
2
▫ LVR (Inorder traversal)
1
V
L
3
R
3
▫ LRV (Postorder traversal)
1
V
L
▫ VLR (Preorder traversal)
2
R
1
2
L
V
3
R
5.3.2 Inorder Traversal
void Tree::Inorder()
{
Inorder(root);
}
void Tree::Inorder(TreeNode *currentNode)
{
if (currentNode)
{
Inorder(currentNode->leftChild);
Visit(currentNode);
Inorder(currentNode->rightChild);
}
}
Example
•
Consider using a binary tree to represent the
following expression.
(((A / B) * C) * D) + E
+
*
*
/
A
E
D
C
B
Visiting order:
A
/
B
*
C
*
D
+
E
5.3.2 Preorder Traversal
• Approach: VLR
+
*
*
/
A
E
D
void Tree::Inorder(TreeNode *currentNode)
{
if (currentNode)
{
Visit(currentNode);
Inorder(currentNode->leftChild);
Inorder(currentNode->rightChild);
}
}
C
B
Visiting order:
+
*
*
/
A
B
C
D
E
5.3.2 Postorder Traversal
• Approach: LRV
+
*
*
/
A
E
D
void Tree::Inorder(TreeNode *currentNode)
{
if (currentNode)
{
Inorder(currentNode->leftChild);
Inorder(currentNode->rightChild);
Visit(currentNode);
}
}
C
B
Visiting order:
A
B
/
C
*
D
*
E
+
5.3.5 Iterative Inorder Traversal
• By using stack.
void Tree::NonrecInorder()
{
Stack S;
TreeNode *currentNode = root;
1. When do we push into the stack?
while (1)
2. When do we pop the stack?
{
while (currentNode)
{
S.Push(currentNode);
currentNode = currentNode->leftChild;
}
if (S.IsEmpty()) return;
currentNode = S.Pop();
Visit(currentNode);
currentNode = currentNode->rightChild;
}
}
5.3.5 Iterative Inorder Traversal
• By using stack.
currentNode:
NULL
A
B
+
*/
+
A
*
*
E
B
/
*
D
*
/
A
C
B
+
Stack
Visiting order:
A
/
B
5.3.6 Level-Order Traversal
• Visiting order in level-order traversal:
1
+
2
*
4
*
6
/
8
A
7
C
9
B
5
D
3
E
5.3.6 Level-Order Traversal
• By using queue.
void Tree::LevelOrder()
{
Queue Q;
TreeNode *currentNode = root;
while (currentNode)
{
Visit(currentNode);
if (currentNode->leftChild) Q.Push(currentNode->leftChild);
if (currentNode->rightChild) Q.Push(currentNode->rightChild);
if (Q.IsEmpty()) return;
currentNode = Q.Pop();
}
}
5.6.1 Priority Queue
• The element to be deleted is the one with highest (or
lowest) priority.
• Consider one insertion and one deletion for an
ordered and a non-ordered list:
Insertion
Deletion
Ordered List
O(n)
O(1)
Non-ordered List
O(1)
O(n)
where n is the number of elements in the list.
▫ Using a heap, both insertion and deletion can be
performed in O(logn) time
5.6.2 Definition of a Max Heap
• A max tree is a tree which the data in each node is
no smaller than those in its children. A max heap
is a max tree which is a complete binary tree at
once.
9
8
3
1
5
4
6
2
1
7
5
4
6
The ADT of MaxHeap
• A heap can be implemented using array
class MaxHeap
{
private:
int *heap;
int heapSize;
int capacity;
};
//element array
//number of elements in heap
//size of the array heap
The Constructor for MaxHeap
• Note: heap[0] is dummy.
MaxHeap::MaxHeap(int theCapacity = 10)
{
if (theCapacity < 1)
throw “Capacity must be >= 1.”;
capacity = theCapacity;
heapSize = 0;
heap = new int [capacity + 1];
}
0
The root is at
heap[1].
dummy
1
2
4
3
5
6
7
5.6.3 Insertion into a Max Heap
• Example: Insert 5 into the heap
1
20
2
15
2
5
14
10
2
5
4
5
6
currentNode:
Inititally: heapSize+1
6
3
3
7
5.6.3 Insertion into a Max Heap
void MaxHeap::Push(int e)
{
if (heapSize+1 == capacity)
Resize();
int currentNode = heapSize + 1;
while (currentNode != 1 && heap[currentNode/2] < e) {
heap[currentNode] = heap[currentNode / 2];
currentNode /= 2;
}
heap[currentNode] = e;
}
Analysis of Push()
• Time complexity:
▫ The insertion begins at a leaf and moves up
toward the root.
▫ the height of a complete binary tree with n
elements is log2 (n  1) , the while loop is iterated
O(logn) times.
▫ Each iteration of this loop takes O(1) time.
▫ Hence, the time complexity of O(logn).
5.6.4 Deletion from a Max Heap
• Example: delete 5 from the heap
1
currentNode:
20
15
2
The element to be popped:
2
14
15
2
5
14
2
10
2
4
5
6
3
7
4
21
20
5.6.4 Deletion from a Max Heap
int MaxHeap::Pop(int e)
{
if (IsEmpty())
throw “Heap is empty.”;
int lastE = heap[heapSize – -];
int currentNode = 1; //root
int Max = heap[currentNode];
int child = 2;
//a child of currentNode
while (child <= heapSize) {
if (child < heapSize && heap[child] < heap[child+1])
child++;
if (lastE >= heap[child]) break ;
heap[currentNode] = heap[child];
currentNode = child;
child *= 2;
}
heap[currentNode] = lastE;
return Max;
}
Analysis of Pop()
• Time complexity:
▫ Suppose the number of elements in the heap is n.
▫ Since the height of a heap is log2 (n  1) , the while
loop is iterated O(logn) times.
▫ Each iteration of this loop takes O(1) time.
▫ Hence, the time complexity of pop() is O(logn).
Part I – Searching and Insertion
5.7.1 Defintion
• A binary search tree has the following properties:
1. The keys in all nodes are distinct.
2. The key in any node is larger than all keys in its
left subtree.
3. The key in any node is smaller than all keys in its
right subtree.
4. The left and right subtrees are also binary trees.
Examples
• Examples of binary search tree
20
25
15
12
30
16
5
26
2
60
40
70
65
80
By using which traversal approach can we output the keys in increasing order?
5.7.2 Searching a Binary Search Tree
• Point: searching a binary tree in a recursive way.
bool BST::Search(int k)
{
return Get(root, k);
}
bool BST::Search (TreeNode *p, int k)
{
if (!p)
return false;
if (p->key == k)
return true;
if (k < p->key) return Search (p->leftChild, k);
if (k > p->key) return Search (p->rightChild, k);
}
5.7.2 Searching a Binary Search Tree
• Searching a binary tree in an iterative way.
bool BST::IterativeSearch (int k)
{
TreeNode *currentNode = root;
while (currentNode)
{
if (k == currentNode->data)
return true;
if (k < currentNode->data)
currentNode = currentNode->leftChild;
if (k > currentNode->data)
currentNode = currentNode->rightChild;
}
return false;
}
Comparison
• Suppose h denote the depth of the tree.
Time
complexity
Recursion
O(h)
Iteration
O(h)
Space
complexity
Recursion
O(h)
Iteration
O(1)
5.7.3 Insertion into a Binary Search Tree
• Point: to find the position to insert first.
• If there is a duplicate key, then the insertion will not be
performed.
• Consider to insert 35 into the tree:
30
40
5
2
30
16
40
5
80
2
35
16
80
5.7.3 Insertion into a Binary Search Tree
bool BST::Insert (int k)
{
TreeNode *p = root, **pp = NULL;
while (p)
{
pp = p;
if (k == p->data)
return false;
if (k < p->data) p = p->leftChild;
if (k > p->data) p = p->rightChild;
}
p = new TreeNode(k);
if (root)
{
if (k < pp->key) pp->leftChild = p;
else (k > pp->key) pp->RightChild = p;
}
else
root = p;
return false;
}