Title: C %20Plus%20Data%20Structures
1C Plus Data Structures
Nell Dale Chapter 7 Programming with
Recursion Modified from the slides by Sylvia
Sorkin, Community College of Baltimore County -
Essex Campus
2Recursive Function Call
- A recursive call is a function call in which the
called function is the same as the one making the
call. -
- In other words, recursion occurs when a function
calls itself! - We must avoid making an infinite sequence of
function calls (infinite recursion).
3Finding a Recursive Solution
- Each successive recursive call should bring you
closer to a situation in which the answer is
known. - A case for which the answer is known (and can be
expressed without recursion) is called a base
case. - Each recursive algorithm must have at least one
base case, as well as the general (recursive) case
4Three-Question Method of verifying recursive
functions
- Base-Case Question Is there a nonrecursive way
out of the function? - Smaller-Caller Question Does each recursive
function call involve a smaller case of the
original problem leading to the base case? - General-Case Question Assuming each recursive
call works correctly, does the whole function
work correctly?
5Writing Recursive Functions
- Get an exact definition of the problem to be
solved. - Determine the size of the problem on this call to
the function. - Identify and solve the base case(s).
- Identify and solve the general case(s) in terms
of a smaller case of the same problem a
recursive call.
6Why use recursion?
Those examples could have been written without
recursion, using iteration instead. The
iterative solution uses a loop, and the recursive
solution uses an if statement. However, for
certain problems the recursive solution is the
most natural solution. This often occurs when
pointer variables are used.
7Recursive Linked List Processing
8struct ListType
- struct NodeType
-
- int info
- NodeType next
-
- class SortedType
- public
-
- . . . // member function prototypes
- private
- NodeType listData
-
-
9RevPrint(listData)
listData
10Base Case and General Case
- A base case may be a solution in terms of a
smaller list. Certainly for a list with 0
elements, there is no more processing to do. - Our general case needs to bring us closer to the
base case situation. That is, the number of list
elements to be processed decreases by 1 with each
recursive call. By printing one element in the
general case, and also processing the smaller
remaining list, we will eventually reach the
situation where 0 list elements are left to be
processed. - In the general case, we will print the elements
of the smaller remaining list in reverse order,
and then print the current pointed to element.
11Using recursion with a linked list
- void RevPrint ( NodeType listPtr )
- // Pre listPtr points to an element of a
list. - // Post all elements of list pointed to by
listPtr have been printed - // out in reverse order.
-
- if ( listPtr ! NULL ) // general case
-
- RevPrint ( listPtr-gt next ) //
process the rest - cout ltlt listPtr-gtinfo ltlt endl //
then print this element -
- // Base case if the list is empty, do
nothing
11
12How Recursion Works
- Static storage allocation associates variable
names with memory locations at compile time. - Dynamic storage allocation associates variable
names with memory locations at execution time.
13When a function is called...
- A transfer of control occurs from the calling
block to the code of the function. It is
necessary that there is a return to the correct
place in the calling block after the function
code is executed. This correct place is called
the return address. - When any function is called, the run-time stack
is used. On this stack is placed an activation
record (stack frame) for the function call.
14Stack Activation Frames
- The activation record stores the return address
for this function call, and also the parameters,
local variables, and the functions return value,
if non-void. - The activation record for a particular function
call is popped off the run-time stack when the
final closing brace in the function code is
reached, or when a return statement is reached in
the function code. - At this time the functions return value, if
non-void, is brought back to the calling block
return address for use there.
15Debugging Recursive Routines
- Using the Three-Question Method.
- Using a branching statement (if/switch).
- Put debug output statement during testing.
-
16Removing Recursion
- When the language doesnt support recursion, or
recursive solution is too costly (space or time),
or - Iteration
- Stacking
17Use a recursive solution when
- The depth of recursive calls is relatively
shallow compared to the size of the problem. - The recursive version does about the same amount
of work as the nonrecursive version. - The recursive version is shorter and simpler than
the nonrecursive solution.
SHALLOW DEPTH EFFICIENCY
CLARITY
18C Plus Data Structures
Nell Dale Chapter 8 Binary Search
Trees Modified from the slides by Sylvia
Sorkin, Community College of Baltimore County -
Essex Campus
19Binary search
- for an element in a sorted list stored
sequentially - in an array O(Log2N)
- in a linked list ? (midpoint ?)
20Goals of this chapter
- Introduce some basic tree vocabulary
- Develop algorithms
- Implement operations needed to use a binary
search tree
21Binary Tree
- A binary tree is a structure in which
- Each node can have at most two children, and
in which a unique path exists from the root to
every other node. - The two children of a node are called the left
child and the right child, if they exist.
22Implementing a Binary Tree with Pointers and
Dynamic Data
V
Q
L
T
A
E
K
S
23Each node contains two pointers
templatelt class ItemType gt struct TreeNode
ItemType info // Data member
TreeNodeltItemTypegt left // Pointer to
left child TreeNodeltItemTypegt right //
Pointer to right child
NULL A 6000
. left . info . right
24// BINARY SEARCH TREE SPECIFICATION templatelt
class ItemType gt class TreeType public
TreeType ( ) // constructor
TreeType ( ) // destructor
bool IsEmpty ( ) const bool IsFull ( )
const int NumberOfNodes ( ) const
void InsertItem ( ItemType item ) void
DeleteItem (ItemType item ) void
RetrieveItem ( ItemType item, bool found )
void PrintTree (ofstream outFile) const
. . . private TreeNodeltItemTypegt
root
24
25TreeTypeltchargt CharBST
Private data root
RetrieveItem
PrintTree . . .
26A Binary Tree
V
Q
L
T
A
E
K
S
Search for S?
27A Binary Search Tree (BST) is . . .
- A special kind of binary tree in which
- 1. Each node contains a distinct data value,
- 2. The key values in the tree can be compared
using greater than and less than, and - 3. The key value of each node in the tree is
- less than every key value in its right subtree,
and greater than every key value in its left
subtree.
28Is F in the binary search tree?
J
T
E
A
V
M
H
P
29Is F in the binary search tree?
J
T
E
A
V
M
H
P
30// BINARY SEARCH TREE SPECIFICATION templatelt
class ItemType gt class TreeType public
TreeType ( ) // constructor
TreeType ( ) // destructor
bool IsEmpty ( ) const bool IsFull (
) const int NumberOfNodes ( ) const
void InsertItem ( ItemType item )
void DeleteItem (ItemType item )
void RetrieveItem ( ItemType item , bool
found ) void PrintTree (ofstream
outFile) const . . . private
TreeNodeltItemTypegt root
30
31// SPECIFICATION (continued) // - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - //
RECURSIVE PARTNERS OF MEMBER FUNCTIONS
templatelt class ItemType gt void PrintHelper
( TreeNodeltItemTypegt ptr, ofstream
outFile ) templatelt class ItemType
gt void InsertHelper ( TreeNodeltItemTypegt
ptr, ItemType item )
templatelt class ItemType gt void
RetrieveHelper ( TreeNodeltItemTypegt ptr,
ItemType item, bool found )
templatelt class ItemType gt void
DestroyHelper ( TreeNodeltItemTypegt ptr )
31
32 templatelt class ItemType gt void
TreeTypeltItemTypegt RetrieveItem ( ItemType
item, bool found
) RetrieveHelper ( root, item, found )
templatelt class ItemType gt void
RetrieveHelper ( TreeNodeltItemTypegt ptr,
ItemType item, bool
found) if ( ptr NULL ) found
false else if ( item lt ptr-gtinfo
) // GO LEFT RetrieveHelper( ptr-gtleft ,
item, found ) else if ( item gt
ptr-gtinfo ) // GO RIGHT RetrieveHelper(
ptr-gtright , item, found ) else
item ptr-gtinfo found true
32
33 templatelt class ItemType gt void
TreeTypeltItemTypegt InsertItem ( ItemType item
) InsertHelper ( root, item )
templatelt class ItemType gt void
InsertHelper ( TreeNodeltItemTypegt ptr,
ItemType item ) if ( ptr NULL )
// INSERT item HERE AS LEAF ptr
new TreeNodeltItemTypegt ptr-gtright NULL
ptr-gtleft NULL ptr-gtinfo item
else if ( item lt ptr-gtinfo ) // GO
LEFT InsertHelper( ptr-gtleft , item )
else if ( item gt ptr-gtinfo ) // GO
RIGHT InsertHelper( ptr-gtright , item )
33
34PrintTree()
- Traverse a list
- -- forward
- -- backward
- Traverse a tree
- -- there are many ways!
35Inorder Traversal A E H J M T Y
Print second
tree
T
E
A
H
M
Y
Print left subtree first
Print right subtree last
36Preorder Traversal J E A H T M Y
Print first
tree
T
E
A
H
M
Y
Print left subtree second
Print right subtree last
37Postorder Traversal A H E M Y T J
Print last
tree
T
E
A
H
M
Y
Print left subtree first
Print right subtree second
38Recursion or Iteration?
Assume the tree is well balanced.
- Is the depth of recursion relatively shallow?
- Yes.
- Is the recursive solution shorter or clearer than
the nonrecursive version? - Yes.
- Is the recursive version much less efficient than
the nonrecursive version? - No.
39Use a recursive solution when (Chpt. 7)
- The depth of recursive calls is relatively
shallow compared to the size of the problem. - The recursive version does about the same amount
of work as the nonrecursive version. - The recursive version is shorter and simpler than
the nonrecursive solution.
SHALLOW DEPTH EFFICIENCY
CLARITY
40Binary Search Trees (BSTs) vs. Linear Lists
- BST
- Quick random-access with the flexibility of a
linked structure - Can be implemented elegantly and concisely using
recursion - Takes up more memory space than a singly linked
list - Algorithms are more complicated
41C Plus Data Structures
Nell Dale Chapter 9 Trees Plus Modified from
the slides by Sylvia Sorkin, Community College of
Baltimore County - Essex Campus
42A Binary Expression Tree is . . .
- A special kind of binary tree in which
- 1. Each leaf node contains a single operand,
- 2. Each nonleaf node contains a single binary
operator, and - 3. The left and right subtrees of an operator
node represent subexpressions that must be
evaluated before applying the operator at the
root of the subtree.
43Levels Indicate Precedence
- When a binary expression tree is used to
represent an expression, the levels of the nodes
in the tree indicate their relative precedence of
evaluation. - Operations at higher levels of the tree are
evaluated later than those below them. The
operation at the root is always the last
operation performed.
44A Binary Expression Tree
Infix ( ( 4 2 ) 3 ) Prefix
4 2 3 Postfix 4 2 3
has operators in order used
45Inorder Traversal (A H) / (M - Y)
Print second
tree
-
A
H
M
Y
Print left subtree first
Print right subtree last
46Preorder Traversal / A H - M Y
Print first
tree
-
A
H
M
Y
Print left subtree second
Print right subtree last
47Postorder Traversal A H M Y - /
Print last
tree
-
A
H
M
Y
Print left subtree first
Print right subtree second
48Function Eval()
- Definition Evaluates the expression
represented by the binary tree. - Size The number of nodes in the tree.
- Base Case If the content of the node is an
operand, Func_value the value of the
operand. - General Case If the content of the node is an
operator BinOperator, - Func_value Eval(left subtree)
-
BinOperator - Eval(right subtree)
49Writing Recursive Functions (Chpt 7)
- Get an exact definition of the problem to be
solved. - Determine the size of the problem on this call to
the function. - Identify and solve the base case(s).
- Identify and solve the general case(s) in terms
of a smaller case of the same problem a
recursive call.
50Eval(TreeNode tree)
Algorithm IF Info(tree) is an operand Return
Info(tree) ELSE SWITCH(Info(tree)) case
Return Eval(Left(tree)) Eval(Right(tree))
case - Return Eval(Left(tree)) -
Eval(Right(tree)) case Return
Eval(Left(tree)) Eval(Right(tree)) case /
Return Eval(Left(tree)) / Eval(Right(tree))
51int Eval ( TreeNode ptr ) // Pre ptr is
a pointer to a binary expression tree. // Post
Function value the value of the expression
represented // by the binary tree pointed to
by ptr. switch ( ptr-gtinfo.whichType )
case OPERAND return
ptr-gtinfo.operand case OPERATOR switch
( tree-gtinfo.operation ) case
return ( Eval ( ptr-gtleft ) Eval (
ptr-gtright ) ) case - return
( Eval ( ptr-gtleft ) - Eval ( ptr-gtright ) )
case return ( Eval (
ptr-gtleft ) Eval ( ptr-gtright ) )
case / return ( Eval ( ptr-gtleft ) /
Eval ( ptr-gtright ) )
51
52A Nonlinked Representation ofBinary Trees
Store a binary tree in an array in such a way
that the parent-child relationships are not lost
53A full binary tree
- A full binary tree is a binary tree in which all
the leaves are on the same level and every non
leaf node has two children. - SHAPE OF A FULL BINARY TREE
54A complete binary tree
- A complete binary tree is a binary tree that is
either full or full through the next-to-last
level, with the leaves on the last level as far
to the left as possible. -
- SHAPE OF A COMPLETE BINARY TREE
55What is a Heap?
- A heap is a binary tree that satisfies these
- special SHAPE and ORDER properties
- Its shape must be a complete binary tree.
- For each node in the heap, the value stored in
that node is greater than or equal to the value
in each of its children.
56And use the numbers as array indexes to store the
tree
tree.nodes
57Parent-Child Relationship?
tree.nodesindex left child
tree.nodesindex2 1 right child
tree.nodesindex2 2 parent
tree.nodes(index-1) / 2 Leaf nodes
tree.nodesnumElements / 2 tree.nodesnumEl
ements - 1
58// HEAP SPECIFICATION // Assumes ItemType
is either a built-in simple data type // or a
class with overloaded realtional
operators. templatelt class ItemType gt struct
HeapType void ReheapDown ( int
root , int bottom ) void ReheapUp (
int root, int bottom ) ItemType
elements // ARRAY to be allocated
dynamically int numElements
58
59ReheapDown(root, bottom)
IF elementsroot is not a leaf Set maxChild
to index of child with larger value IF
elementsroot lt elementsmaxChild)
Swap(elementsroot, elementsmaxChild)
ReheapDown(maxChild, bottom)
60ReheapDown()
// IMPLEMENTATION OF RECURSIVE HEAP MEMBER
FUNCTIONS templatelt class ItemType gt void
HeapTypeltItemTypegtReheapDown ( int root, int
bottom ) // Pre root is the index of the node
that may violate the heap // order
property // Post Heap order property is
restored between root and bottom int
maxChild int rightChild int
leftChild leftChild root 2 1
rightChild root 2 2
60
61 if ( leftChild lt bottom ) //
ReheapDown continued if ( leftChild
bottom ) maxChild leftChld else
if (elements leftChild lt elements
rightChild ) maxChild rightChild
else maxChild leftChild if (
elements root lt elements maxChild )
Swap ( elements root , elements maxChild
) ReheapDown ( maxChild, bottom )
61
62Priority Queue
- A priority queue is an ADT with the property that
only the highest-priority element can be accessed
at any time.
63Priority Queue ADT Specification
- Structure
- The Priority Queue is arranged to support access
to the highest priority item - Operations
- MakeEmpty
- Boolean IsEmpty
- Boolean IsFull
- Enqueue(ItemType newItem)
- Dequeue(ItemType item)
-
63
64Implementation Level
- Algorithm
- Dequeue() O(log2N)
- Set item to root element from queue
- Move last leaf element into root position
- Decrement numItems
- items.ReheapDown(0, numItems-1)
- Enqueue() O(log2N)
- Increment numItems
- Put newItem in next available position
- items.ReheapUp(0, numItems-1)
-
-
64
65Comparison of Priority Queue Implementations
Enqueue Dequeue
Heap O(log2N) O(log2N)
Linked List O(N) O(1)
Binary Search Tree
Balanced O(log2N) O(log2N)
Skewed O(N) O(N)
Trade-offs read Text page 548
65
66End