You are on page 1of 104

Bilgisayar Mühendisliği Bölümü

DATA STRUCTURES
AND
ALGORITHMS

Lecture Notes 10
Trees

Spring 2008

GIT – Computer Engineering Department


Chapter Outline
 How trees organize information hierarchically
 Using recursion to process trees
 The different ways of traversing a tree
 Binary trees, Binary Search trees, and Heaps
 Implementing binary trees, binary search trees,
heaps
– Using linked data structures and arrays
 Using binary search trees for efficient data lookup
 Using Huffman trees for compact character storage

GIT – Computer Engineering Department 2


Chapter Outline
 How trees organize information hierarchically
 Using recursion to process trees
 The different ways of traversing a tree
 Binary trees, Binary Search trees, and Heaps
 Implementing binary trees, binary search trees,
heaps
– Using linked data structures and arrays
 Using binary search trees for efficient data lookup
 Priority Queues
– Heaps
 Using Huffman trees for compact character storage

GIT – Computer Engineering Department 3


TREES: Definition
Recursive Definition : Tree is a collection of nodes
 A tree can be empty
 A tree contains zero or more subtrees T1, T2 ,… Tk
connected to a root node by edges

GIT – Computer Engineering Department 4


Tree Terminology
 Each node may have 0 or more successors
– (Unlike a list, which has 0 or 1 successor)
 Each node has exactly one predecessor
– Except the starting / top node, called the root
 Links from node to its successors are branches
 Successors of a node are called its children
 Predecessor of a node is called its parent
 Nodes with same parent are siblings
 Nodes with no children are called leaves
 We also use words like ancestor and descendent

GIT – Computer Engineering Department 5


Tree Terminology (2)

GIT – Computer Engineering Department 6


Tree Terminology (3)
 Subtree of a node: A tree whose root is a child of that node
 Path : a sequence of nodes n1, n2, … nk,
– where ni is the parent of ni+1 , 1≤i<k
 Lenght : number of edges on the path (k-1)
 Depth : depth of ni is the lenght of unique path from the root
to ni
– depth of root is 0
– depth of other nodes = 1 + depth of parent
– depth of a tree = depth of the deepest leaf
 Height : height of ni is the lenght of the longest path from ni
to a leaf
– height of a leaf is 0
– height of a tree = height of the root = depth of the tree

GIT – Computer Engineering Department 7


Tree Terminology (4)

Depth 0
(root)
Depth 1

Depth 1
Depth 2

GIT – Computer Engineering Department 8


Tree Terminology (5)

GIT – Computer Engineering Department 9


General Tree Example
 One of the most popular applications of trees is the
directory structure of O/S

GIT – Computer Engineering Department 10


General Tree Example
 Family Tree (Descendants of William I)

GIT – Computer Engineering Department 11


Binary Trees
 Binary tree: a node has at most 2 non-empty subtrees
 Set of nodes T is a binary tree if either of these is true:
– T is empty
– Root of T has two subtrees, both binary trees

This is a
binary tree

GIT – Computer Engineering Department 12


Examples of Binary Trees (1)
 Expression tree
– Non-leaf (internal) nodes contain operators
– Leaf nodes contain operands

GIT – Computer Engineering Department 13


Expression Trees
 Entire tree represents (a+(b*c))+(((d*e)+f)*g)
– Left subtree represents a+(b*c)
– Right subtree represents ((d*e)+f)*g

GIT – Computer Engineering Department 14


Examples of Binary Trees (2)
 Huffman tree
– Represents Huffman codes for characters
appearing in a file or stream
– Huffman code may use different numbers of bits
to encode different characters
– ASCII or Unicode uses a fixed number of bits for
each character

GIT – Computer Engineering Department 15


Huffman Trees

Code for b = 100000


Code for w = 110001
Code for s = 0011
Code for e = 010

GIT – Computer Engineering Department 16


Examples of Binary Trees (3)
Binary search trees
 Elements in left subtree < element in subtree root
 Elements in right subtree > element in subtree root

Search algorithm:
1. if the tree is empty, return NULL
2. if target equals to root node’s data, return that data
3. if target < root node data, return search(left subtree)
4. otherwise return search(right subtree)

GIT – Computer Engineering Department 17


Binary Search Trees
Which one of the trees below is binary search tree ?

GIT – Computer Engineering Department 18


Fullness and Completeness
 (In computer science) trees grow from the top down
 New values inserted in new leaf nodes
 In a full tree, every node has 0 or 2 non-null children
 A complete tree of height h is filled up to depth h-1, and, at
depth h, any unfilled nodes are on the right.

GIT – Computer Engineering Department 19


General (Non-Binary) Trees
 Nodes can have any number of children

GIT – Computer Engineering Department 20


Implementation of General Trees
 Each node contains a pointer to each of its children
– number of children would be large
 Each node contains an array of pointers to its
children
– number of children may vary greatly (waste of space)

GIT – Computer Engineering Department 21


Implementation of General Trees
 Each node contains a linked list of the children

struct TreeNode {
. . .
Object element;
TreeNode *firstChild;
TreeNode *nextSibling;
}

GIT – Computer Engineering Department 22


Implementation of General
Trees
This implementation can be considered as a binary tree.
 A general tree can be represented
using a binary tree

Left link is to first child


Right link is to next younger sibling

GIT – Computer Engineering Department 23


Traversals of Binary Trees
 Often want to iterate over and to process
nodes of a tree
– Can walk the tree and visit the nodes in an order
– This process is called tree traversal
 Three kinds of binary tree traversal:
– Preorder
– Inorder
– Postorder
 According to order of subtrees
– node w.r.t. its children
GIT – Computer Engineering Department 24
Binary Tree Traversals (2)
 Preorder: Visit root, traverse left, traverse right
 Inorder: Traverse left, visit root, traverse right
 Postorder: Traverse left, traverse right, visit root
Algorithm for Algorithm for Algorithm for
Preorder Traversal Inorder Traversal Postorder Traversal
1. if the tree is empty 1. if the tree is empty 1. if the tree is empty
2. Return 2. Return 2. Return
else else else
3. Visit the root 3. Inorder traverse 3. Postorder traverse
4. Preorder traverse the left subtree the left subtree
the left subtree 4. Visit the root 4. Postorder traverse
5. Preorder traverse 5. Inorder traverse the right subtree
the right subtree the right subtree 5. Visit the root.

GIT – Computer Engineering Department 25


Visualizing Tree Traversals
 Can visualize traversal by imagining a mouse that
walks along outside the tree
 If mouse keeps the tree on its left, it traces a route
called the Euler tour:
 Preorder: record node first time mouse is there
 Inorder: record after mouse traverses left subtree
 Postorder: record node last time mouse is there

GIT – Computer Engineering Department 26


Visualizing Tree Traversals (2)

Preorder:
a, b, d, g, e,
h, c, f, i, j

GIT – Computer Engineering Department 27


Visualizing Tree Traversals (3)

Inorder:
d, g, b, h, e,
a, i, f, j, c

GIT – Computer Engineering Department 28


Visualizing Tree Traversals (4)

Postorder:
g, d, h, e, b,
i, j, f, c, a

GIT – Computer Engineering Department 29


Traversals of Binary Search Trees
 Inorder traversal of a binary search tree 
Nodes are visited in order of increasing data
value

GIT – Computer Engineering Department 30


Traversals of General Trees
 Inorder traversal does not apply.
 Preorder and postorder traversals are similar.

GIT – Computer Engineering Department 31


Traversals of General Trees
 List all directories and files in a directory

GIT – Computer Engineering Department 32


Traversals of General Trees
 EX: List all directories and files in a directory
– Preorder traversal!

void FileSystem::listAll(int depth = 0)const


{
printName(depth);
if (isDirectory())
for each file c in this directory
(for each child)
c.listAll(depth+1);
}

GIT – Computer Engineering Department 33


Traversals of General Trees
 List all directories and files in a directory
– How to write their size, as well?

GIT – Computer Engineering Department 34


Traversals of General Trees
 EX: Calculate the size of a directory
– Postorder traversal!

int FileSystem::size () const


{
int totalSize = sizeOfThisFile ();
if (isDirectory())
for each file c in this directory
totalSize += c.size();
return totalsize;
}

GIT – Computer Engineering Department 35


Traversals of Expression Trees
 Inorder traversal results in infix form
– insert parentheses where they belong for infix form
 Postorder traversal results in postfix form
 Preorder traversal results in prefix form

Infix form (x + y) * ((a + b) / c)


Postfix form: x y + a b + c / *
Prefix form: * + x y / + a b c

GIT – Computer Engineering Department 36


Constructing an Expression Tree
Algorithm to convert a postfix expresion into
an expression tree
– read the expression one symbol at a time.
– if the symbol is operand
• create a one-node tree
• push the tree onto a stack
– if the symbol is operator
• pop two trees T1 and T2 from the stack
• form a new tree whose root is the operator and whose
left and right subtrees are T2 and T1 respectively
• This new tree is pushed onto the stack

GIT – Computer Engineering Department 37


Example:
input is ab+cde+**
 First two symbols are
operands
– create one-node trees
– push pointers to them onto
a stack
 Next + is read
– pointers to trees are poped
– a new tree is formed
– a pointer to it is pushed
onto the stack

GIT – Computer Engineering Department 38


Example:

input is ab+cde+**
 c, d, e are read
– for each a one-node tree
is created
– A pointer to the
corresponding tree is
pushed onto the stack.

GIT – Computer Engineering Department 39


Example:

input is ab+cde+**
 + is read
– two trees are merged

GIT – Computer Engineering Department 40


Example:

input is ab+cde+**
 * is read
– pop two tree pointers
and form a new tree
with a * as root

GIT – Computer Engineering Department 41


Example:
input is ab+cde+**
 Last symbol is read
– two trees are merged
– a pointer to the final tree is left on the stack

GIT – Computer Engineering Department 42


Chapter Outline
 How trees organize information hierarchically
 Using recursion to process trees
 The different ways of traversing a tree
 Binary trees, Binary Search trees
 Implementing binary trees, binary search trees
– Using linked data structures and arrays
 Using binary search trees for efficient data lookup
 Using Huffman trees for compact character storage

GIT – Computer Engineering Department 43


Chapter Outline
 How trees organize information hierarchically
 Using recursion to process trees
 The different ways of traversing a tree
 Binary trees, Binary Search trees, and Heaps
 Implementing binary trees, binary search trees,
heaps
– Using linked data structures and arrays
 Using binary search trees for efficient data lookup
 Priority Queues
– Heaps
 Using Huffman trees for compact character storage

GIT – Computer Engineering Department 44


The BTNode Class
 Like linked list, a node has data + links to successors
 Data is reference to object of type E
 Binary tree node has links for left and right subtrees

GIT – Computer Engineering Department 45


The Binary_Tree Class

GIT – Computer Engineering Department 46


Code for BTNode
/** A node for a Binary Tree. */
template<typename Item_Type>
struct BTNode
{
// Data Fields
Item_Type data;
BTNode<Item_Type>* left;
BTNode<Item_Type>* right;

// Constructor
BTNode(const Item_Type& the_data,
BTNode<Item_Type>* left_val = NULL,
BTNode<Item_Type>* right_val = NULL) :
data(the_data), left(left_val), right(right_val) {}

// Destructor (to avoid warning message)


virtual ~BTNode() {}

GIT – Computer Engineering Department 47


Code for BTNode (2)
// to_string
virtual std::string to_string() const {
std::ostringstream os;
os << data;
return os.str();
}
}; // End BTNode

// Overloading extraction operator


template <typename Item_Type>
std::ostream& operator<<(std::ostream& out,
const BTNode<Item_Type>& node) {
return out << node.to_string();
}

GIT – Computer Engineering Department 48


Design of Binary_Tree class

Data Field Attribute


BTNode<Item_Type>* root Pointer to the root of the tree.
Constructor Behavior
Binary_Tree() Construct an empty binary tree.
Binary_Tree(const Item_Type& the_data, Construct a binary tree with the
const Binary_Tree<Item_Type>& left_child, given data at the root and the
const Binary_Tree<Item_Type>& right_child) two given subtrees.

GIT – Computer Engineering Department 49


Design of Binary_Tree class (2)

Function Behavior
Binary_Tree<Item_Type> get_left_subtree() Returns the left subtree.
const
Binary_Tree<Item_Type> get_right_subtree() Returns the right subtree.
const
const Item_Type& get_data() const Returns the data in the root.
bool is_leaf() const Returns true if this tree is a leaf.
bool is_null() const Returns true if this tree is an
empty tree.
string to_string() const Returns a string representation
of the tree.
static Binary_Tree<Item_Type> Constructs a binary tree by
read_binary_tree(std::istream& in) reading its data from input
stream in.

GIT – Computer Engineering Department 50


Definition of Binary_Tree class
template<typename Item_Type>
class Binary_Tree
{
public:

// Constructors and Functions


Binary_Tree() : root(NULL) {}

Binary_Tree(const Item_Type& the_data,


const Binary_Tree<Item_Type>& left_child
= Binary_Tree(),
const Binary_Tree<Item_Type>& right_child
= Binary_Tree()):
root(new BTNode<Item_Type>(the_data, left_child.root,
right_child.root)) {}

virtual ~Binary_Tree() {} // Do nothing.

GIT – Computer Engineering Department 51


Definition of Binary_Tree class (2)
Binary_Tree<Item_Type> get_left_subtree() const;

Binary_Tree<Item_Type> get_right_subtree() const;

const Item_Type& get_data() const;

bool is_null() const;

bool is_leaf() const;

virtual std::string to_string() const;

static Binary_Tree<Item_Type>
read_binary_tree(std::istream& in);

std::string root_to_string() const {


return root->to_string();
}

GIT – Computer Engineering Department 52


Definition of Binary_Tree class (3)

protected:

// Protected constructor
Binary_Tree(BTNode<Item_Type>* new_root) :
root(new_root) {}

// Data Field
BTNode<Item_Type>* root;

}; // End Binary_Tree

GIT – Computer Engineering Department 53


Get subtree functions
template<typename Item_Type>
Binary_Tree<Item_Type>
Binary_Tree<Item_Type>::get_left_subtree() const {
if (root == NULL) {
throw std::invalid_argument
("get_left_subtree on empty tree");
}
return Binary_Tree<Item_Type>(root->left);
}

template<typename Item_Type>
Binary_Tree<Item_Type>
Binary_Tree<Item_Type>::get_right_subtree() const {
if (root == NULL) {
throw std::invalid_argument
("get_right_subtree on null tree");
}
return Binary_Tree<Item_Type>(root->right);
}

GIT – Computer Engineering Department 54


is_leaf

template<typename Item_Type>
bool Binary_Tree<Item_Type>::is_leaf() const {
if (root != NULL) {
return root->left == NULL && root->right == NULL;
} else
return true;
}

GIT – Computer Engineering Department 55


to_string

template<typename Item_Type>
std::string Binary_Tree<Item_Type>::to_string() const {
std::ostringstream os;
if (is_null())
os << "NULL\n";
else {
os << *root << '\n';
os << get_left_subtree().to_string();
os << get_right_subtree().to_string();
}
return os.str();
}

GIT – Computer Engineering Department 56


Overview of Binary Search Tree
Binary search tree definition:
T is a binary search tree if either of these is true
– T is empty; or
– Root has two subtrees:
• Each is a binary search tree
• Value in root > all values of the left subtree
• Value in root < all values in the right subtree

GIT – Computer Engineering Department 57


Binary Search Tree Example

GIT – Computer Engineering Department 58


Searching a Binary Tree

GIT – Computer Engineering Department 59


Searching a Binary Tree: Algorithm

1. if root is NULL
2. item not in tree: return NULL
3. compare target and root->data
4. if they are equal
5. target is found, return root->data
6. else if target < root->data
7. return search(left subtree)
8. else
9. return search(right subtree)

GIT – Computer Engineering Department 60


Design of Binary_Search_Tree

GIT – Computer Engineering Department 61


Definition of Binary_Search_Tree Class

template<typename Item_Type>
class Binary_Search_Tree : public Binary_Tree<Item_Type>
{
public:
// Constructor
Binary_Search_Tree() : Binary_Tree<Item_Type>() {}

// Public Member Functions


virtual bool insert(const Item_Type& item);

virtual bool erase(const Item_Type& item);

const Item_Type* find(const Item_Type& target) const;

GIT – Computer Engineering Department 62


Binary_Search_Tree Definition (2)
private:

// Private Member Functions


virtual bool insert(BTNode<Item_Type>*& local_root,
const Item_Type& item);

virtual bool erase(BTNode<Item_Type>*& local_root,


const Item_Type& item);

const Item_Type* find(BTNode<Item_Type>* local_root,


const Item_Type& target) const;

virtual void replace_parent(


BTNode<Item_Type>*& old_root,
BTNode<Item_Type>*& local_root);

}; // End binary search tree

GIT – Computer Engineering Department 63


The Find Function
template<typename Item_Type>
const Item_Type* Binary_Search_Tree<Item_Type>::find(
const Item_Type& item) const {
return find(this->root, item);
}

template<typename Item_Type>
const Item_Type* Binary_Search_Tree<Item_Type>::find(
BTNode<Item_Type>* local_root,
const Item_Type& target) const {
if (local_root == NULL)
return NULL;
if (target < local_root->data)
return find(local_root->left, target);
else if (local_root->data < target)
return find(local_root->right, target);
else
return &(local_root->data);
}

GIT – Computer Engineering Department 64


Insertion into a Binary Search Tree

GIT – Computer Engineering Department 65


Binary Search Tree Add Algorithm
1. if root is NULL
2. replace empty tree with new data leaf; return true
3. if item equals root->data
4. return false
5. if item < root->data
6. return insert(left subtree, item)
7. else
8. return insert(right subtree, item)

GIT – Computer Engineering Department 66


The insert function
template<typename Item_Type>
bool Binary_Search_Tree<Item_Type>::insert(
const Item_Type& item) {
return insert(this->root, item);
}

template<typename Item_Type>
bool Binary_Search_Tree<Item_Type>::insert(
BTNode<Item_Type>*& local_root,
const Item_Type& item) {
if (local_root == NULL) {
local_root = new BTNode<Item_Type>(item);
return true;
} else {
if (item < local_root->data)
return insert(local_root->left, item);
else if (local_root->data < item)
return insert(local_root->right, item);
else
return false;
}
}
GIT – Computer Engineering Department 67
Removing from a Binary Search Tree
 Item not present: do nothing
 Item present in leaf: remove leaf (change to null)
 Item in non-leaf with one child:
Replace current node with that child
 Item in non-leaf with two children?
– Find largest item in the left subtree
– Recursively remove it
– Use it as the parent of the two subtrees
– (Could use smallest item in right subtree)

GIT – Computer Engineering Department 68


Removing from a Binary Search Tree (2)

GIT – Computer Engineering Department 69


The erase function
template<typename Item_Type>
bool Binary_Search_Tree<Item_Type>::erase(
const Item_Type& item) {
return erase(this->root, item);
}

template<typename Item_Type>
bool Binary_Search_Tree<Item_Type>::erase(
BTNode<Item_Type>*& local_root,
const Item_Type& item) {
if (local_root == NULL) {
return false;
} else {
if (item < local_root->data)
return erase(local_root->left, item);
else if (local_root->data < item)
return erase(local_root->right, item);
else { // Found item
. . .

GIT – Computer Engineering Department 70


The erase function (2)

BTNode<Item_Type>* old_root = local_root;


if (local_root->left == NULL) {
local_root = local_root->right;
} else if (local_root->right == NULL) {
local_root = local_root->left;
} else {
replace_parent(old_root, old_root->left);
}
delete old_root;
return true;
}
}

GIT – Computer Engineering Department 71


replace_parent

template<typename Item_Type>
void Binary_Search_Tree<Item_Type>::replace_parent(
BTNode<Item_Type>*& old_root,
BTNode<Item_Type>*& local_root) {
if (local_root->right != NULL) {
replace_parent(old_root, local_root->right);
} else {
old_root->data = local_root->data;
old_root = local_root;
local_root = local_root->left;
}
}

GIT – Computer Engineering Department 72


Using Binary Search Trees
 Want an index of words in a paper, by line #
 Put word/line # strings into a binary search tree
– “a, 3”, “a, 13”, “are, 3” and so on

GIT – Computer Engineering Department 73


build_index
void build_index(Binary_Search_Tree<string>& index,
istream& in)
{
string next_line;
int line_num = 0;
while (getline(in, next_line)) {
line_num++;
String_Tokenizer tokenizer(next_line, " ,.:-!?/%\'\"");
while (tokenizer.has_more_tokens()) {
string word = tokenizer.next_token();
to_lower(word);
ostringstream os;
os << word << ", " << right << setw(3) << line_num;
index.insert(os.str());
}
}
}

GIT – Computer Engineering Department 74


Binary Search Trees
 Performance?
– Average BST performance is O(log n)
• Its rare worst case is O(n)
• Happens (for example) with sorted input
– Ordered list performance is O(n)
 Later consider guaranteeing O(log n) trees

GIT – Computer Engineering Department 75


Chapter Outline
 How trees organize information hierarchically
 Using recursion to process trees
 The different ways of traversing a tree
 Binary trees, Binary Search trees, and Heaps
 Implementing binary trees, binary search trees,
heaps
– Using linked data structures and arrays
 Using binary search trees for efficient data lookup
 Priority Queues
– Heaps
 Using Huffman trees for compact character storage

GIT – Computer Engineering Department 76


Priority Queue ADT: Model
 Priority Queue is a data structure that allows
at least two operations
– insert
• equivalent to push operation in queue ADT
– deleteMin
• finds, returns and removes the minimum element in
priority queue
• equivalent to pop operation in queue ADT

GIT – Computer Engineering Department 77


Priority Queue ADT: Applications
Many applications
 Printer queues
 Multiuser O/S process scheduling
 Many graph algorithms

GIT – Computer Engineering Department 78


How to Implement a Priority Queue
 Linked list
– Unsorted
• insertion takes O(1) time
• deletion takes O(N) time
– Sorted
• insertion takes O(N) time
• deletion takes O(1) time
 Binary Search Tree
– Insertion and deletion takes O(logN) time
– Uses pointers
• Complicated
• Constant running time is large
• Supports more functions that are not necessary

GIT – Computer Engineering Department 79


How to Implement a Priority Queue
 Heap
– Does not use pointers
– N insertion takes O(N) time
• Insertion takes O(1) amortized
– DeleteMin takes O(logN)

GIT – Computer Engineering Department 80


Heap Structures
 Binary Heap
 d-Heap
 Leftist Heap
 Binomial Heap
 Fibonacci Heap

Binary heap is very common !


– We will refer to binary heaps as “heaps”

GIT – Computer Engineering Department 81


Heaps
 A heap orders its nodes, but in a way different from
a binary search tree
– Value in a node is larger than the value at its parent
 A complete tree is a heap if
– The value in the root is the largest of the tree
– Every subtree is also a heap
 Equivalently, a complete tree is a heap if
– Node value > child value, for each child of the node
 Note: This use of the word “heap” is entirely
different from the heap that is the allocation area in
C++

GIT – Computer Engineering Department 82


Example of a Heap

• if heap has height h then number of nodes is


between 2h and 2h+1 -1
• height of a heap with N nodes is O(logN)

GIT – Computer Engineering Department 83


Inserting an Item into a Heap
1. Insert the item in the next position across
the bottom of the complete tree: preserve
completeness
2. Restore “heap-ness”:
1. while new item not root and > parent
2. swap new item with parent

GIT – Computer Engineering Department 84


Example Inserting into a Heap

GIT – Computer Engineering Department 85


Removing an Item from a Heap
 Removing an item is always from the top:
– Remove the root (minimum element):
• Leaves a “hole”:
– Fill the “hole” with the last item (lower right-hand) L
• Preserve completeness
– Swap L with largest child, as necessary
• Restore “heap-ness”

GIT – Computer Engineering Department 86


Example Removing From a Heap

GIT – Computer Engineering Department 87


Implementing a Heap
 Recall: a heap is a complete binary tree
– (plus the heap ordering property)
 A complete binary tree fits nicely in an array:
– The root is at index 0
– Children of node at index i are at indices 2i+1, 2i+2
– Where is the parent of a node?
11 0

3
8 1 7 2 0 1 2 3 4 5

11 8 7 2 5 4

2 3 5 4 4 5

GIT – Computer Engineering Department 88


Inserting into a vector Heap
1. Insert new item at end; set child to size-1
2. Set parent to (child – 1)/2
3. while (parent ≥ 0 and a[parent] < a[child])
4. Swap a[parent] and a[child]
5. Set child equal to parent
6. Set parent to (child – 1) / 2

GIT – Computer Engineering Department 89


Deleting from a vector Heap
1. Set a[0] to a[size-1], and shrink size by 1
2. Set parent to 0
3. while (true)
4. Set lc to 2 * parent + 1, and rc to lc + 1
5. If lc ≥ size, break out of while (we’re done)
6. Set maxc to lc
7. If rc < size and a[rc] > a[lc], set maxc to rc
8. If a[parent] ≥ a[maxc], break (we’re done)
9. Swap a[parent] and a[maxc]; set parent to maxc

GIT – Computer Engineering Department 90


Performance of Heap
 A complete tree of height h-1 has:
– Less than 2h nodes
– At least 2h-1 nodes
 Thus complete tree of n nodes has height O(log n)
 Insertion and deletion at most do constant amount
of work at each level
 Thus these operations are O(log n), always
 Heap forms the basis of heapsort algorithm (Ch. 10)

GIT – Computer Engineering Department 91


Design of Class KW::priority_queue

Data Field Attribute


Container the_data A sequential container to hold the data. A
std::vector is the default, but a deque may
also be used.
Compare comp The function object that performs
comparison. By default, this function is
equivalent to operator<.
Function Behavior
void push(const Item_Type&) Inserts an item into the queue.
void pop() Removes the largest entry.
const Item_Type& top() const Returns the largest entry without removing it.
size_t size() const Returns the number of items in the priority
queue.
bool empty() const Returns true if the queue is empty.

GIT – Computer Engineering Department 92


Definition of class KW::priority_queue

template <typename Item_Type,


typename Container = std::vector<Item_Type>,
typename Compare = std::less<Item_Type> >
class priority_queue {
public:
priority_queue() {}
void push(const Item_Type& item);
void pop();
bool empty() const {return the_data.empty();}
int size() const {return the_data.size();}
const Item_Type& top() const {return the_data.front();}

private:
Container the_data;
Compare comp;
};

GIT – Computer Engineering Department 93


The push function
template<typename Item_Type, typename Container,
typename Compare>
void
priority_queue<Item_Type,
Container,
Compare>::push(const Item_Type& item) {
the_data.push_back(item);
int child = size() - 1;
int parent = (child - 1) / 2;
// Reheap
while (parent >= 0
&& comp(the_data[parent], the_data[child])) {
std::swap(the_data[child], the_data[parent]);
child = parent;
parent = (child - 1) / 2;
}
}

GIT – Computer Engineering Department 94


The pop function
template<typename Item_Type, typename Container, typename Compare>
void
priority_queue<Item_Type, Container, Compare>::pop() {
if (size() == 1) { the_data.pop_back(); return; }
std::swap(the_data[0], the_data[size() - 1]);
the_data.pop_back();
int parent = 0;
while (true) {
int left_child = 2 * parent + 1;
if (left_child >= size()) break; // out of heap
int right_child = left_child + 1;
int max_child = left_child;
if (right_child < size()
&& comp(the_data[left_child], the_data[right_child]))
max_child = right_child;
if (comp(the_data[parent], the_data[max_child])) {
std::swap(the_data[max_child], the_data[parent]);
parent = max_child;
}
else break;
}
}
GIT – Computer Engineering Department 95
Huffman Trees
Problem Input: A set of symbols, each with a
frequency of occurrence.
Desired output: A Huffman tree
– giving a code that minimizes the bit length of strings
(consisting of those symbols with that frequency of
occurrence)
Strategy:
 Starting with single-symbol trees,
 repeatedly combine the two lowest-frequency trees,
– giving one new tree
– frequency = sum of the frequencies of two trees
 Stop when we have a single tree.

GIT – Computer Engineering Department 96


Huffman Trees (2)
Implementation approach:
– Use a priority queue to find lowest frequency trees
– Use binary trees to represent the Huffman (de)coding
trees
Example: b=13, c=22, d=32 a=64 e=103
Combine b and c: bc=35
Combine d and bc: d(bc)=67
Combine a and d(bc): a(d(bc))=131
Combine e and a(d(bc)): e(a(d(bc)))=234 ... done

GIT – Computer Engineering Department 97


Huffman Tree Example

0 1

0 e=103 0 1

10 a=64
0 1

110 d=32
0 1

1110 b=13 c=22 1111

GIT – Computer Engineering Department 98


Design of Class Huffman_Tree

Data Field Attribute


Binary_Tree<Huff_Data> huff_tree The Huffman tree
Function Behavior
void build_tree(const Builds the Huffman tree using the given
vector<Huff_Data>& symbols) alphabet and weights.
string decode(const string& Decodes a message using the generated
coded_message) const Huffman tree.
void print_code(ostream& out) Outputs the resulting code.
const

GIT – Computer Engineering Department 99


The struct Huff_Data
struct Huff_Data
{
//Data Fields
/** The weight or probability assigned to this HuffData*/
double weight;
/** The alphabet symbol if this is a leaf */
char symbol;
// Constructor
Huff_Data(double w, char c) : weight(w), symbol(c) {}
};

// Ostream operator for Huff_Data


std::ostream& operator<<(std::ostream&, const Huff_Data&);

GIT – Computer Engineering Department 100


The Comparator for Huffman_Trees

struct Compare_Huffman_Trees
{
bool operator()(const Binary_Tree<Huff_Data>& left_tree,
const Binary_Tree<Huff_Data>& right_tree) {
double wLeft = left_tree.get_data().weight;
double wRight = right_tree.get_data().weight;
return wLeft > wRight;
}
};

GIT – Computer Engineering Department 101


The build_tree function
void Huffman_Tree::build_tree(
const std::vector<Huff_Data>& symbols) {
priority_queue<Binary_Tree<Huff_Data>,
std::vector<Binary_Tree<Huff_Data> >,
Compare_Huffman_Trees> the_queue;
for (size_t i = 0; i < symbols.size(); i++) {
the_queue.push(Binary_Tree<Huff_Data>(symbols[i]));
}
// Build the tree
while (the_queue.size() > 1) {
Binary_Tree<Huff_Data> left = the_queue.top();
the_queue.pop();
Binary_Tree<Huff_Data> right = the_queue.top();
the_queue.pop();
double wl = left.get_data().weight;
double wr = right.get_data().weight;
Huff_Data sum(wl + wr, 0);
Binary_Tree<Huff_Data> new_tree(sum, left, right);
the_queue.push(new_tree);
}
huff_tree = the_queue.top();
the_queue.pop();
}
GIT – Computer Engineering Department 102
The print_code function
void Huffman_Tree::print_code(ostream& out, string code,
const Binary_Tree<Huff_Data>& tree) {
Huff_Data the_data = tree.get_data();
if (the_data.symbol != 0) {
if (the_data.symbol == ' ') {
out << "space: " << code << '\n';
} else {
out << the_data.symbol << ": " << code << '\n';
}
} else {
print_code(out, code + "0", tree.get_left_subtree());
print_code(out, code + "1", tree.get_right_subtree());
}
}

GIT – Computer Engineering Department 103


The decode function
string Huffman_Tree::decode(const string& coded_message) {
string result;
Binary_Tree<Huff_Data> current_tree = huff_tree;
for (size_t i = 0; i < coded_message.length(); i++) {
if (coded_message[i] == '1') {
current_tree = current_tree.get_right_subtree();
} else {
current_tree = current_tree.get_left_subtree();
}
if (current_tree.is_leaf()) {
Huff_Data the_data = current_tree.get_data();
result += the_data.symbol;
current_tree = huff_tree;
}
}
return result;
}

GIT – Computer Engineering Department 104

You might also like