0% found this document useful (0 votes)
33 views64 pages

IE2108 Part B (LKH) For Wks 4&5

Recursion is a process where an algorithm calls itself to solve smaller instances of a problem, stopping when a base case is reached. The document compares iterative and recursive methods, provides examples of recursive functions like factorial and array reversal, and discusses the time complexity of recursive algorithms. It also covers data structures such as arrays, linked lists, stacks, and queues, along with their operations and implementations.

Uploaded by

Brian lee
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
33 views64 pages

IE2108 Part B (LKH) For Wks 4&5

Recursion is a process where an algorithm calls itself to solve smaller instances of a problem, stopping when a base case is reached. The document compares iterative and recursive methods, provides examples of recursive functions like factorial and array reversal, and discusses the time complexity of recursive algorithms. It also covers data structures such as arrays, linked lists, stacks, and queues, along with their operations and implementations.

Uploaded by

Brian lee
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 64

WHAT IS RECURSION?

 Recursion is a repetitive process


in which an algorithm calls itself
 Each recursive call solves an
identical, but smaller, problem.
 A test for the base case (initial
condition) enables the recursive
calls to stop

61
ITERATIVE METHOD VS. RECURSIVE ALGORITHM

(Using iterative method)

Recurrence relation: an equation that relates the 𝑛th element, 𝑎𝑛 , of a


sequence to some of its predecessors, 𝑎0 , 𝑎1 , … , 𝑎𝑛−1 .

We also need an initial condition or base case that provides the values for a
finite number of elements of the sequence initially
62
HOW DO I WRITE A RECURSIVE FUNCTION?

 Determine the input size


 Determine the base case(s): the one for which the answer is known
 Determine the general case: the one where the problem is expressed as a
smaller version of itself

63
EXAMPLE: FACTORIAL FUNCTION

Given that
𝑛! = 1 · 2 · 3 · ··· · 𝑛 − 1 ⋅ 𝑛
0! = 1 by definition Base case

Let 𝑓(𝑛) = 𝑛! = 𝑛(𝑛 − 1)!


Hence, 𝑓 𝑛 = 𝑛 ⋅ 𝑓(𝑛 − 1)
General case

64
EXAMPLE: PYTHON CODE FOR THE FACTORIAL FUNCTION

def fact(n):
if n == 0: Sample output
return 1
else:
Enter n: 4
return n*fact(n-1) Recursive call
factorial(4) = 24
n = int(input("Enter n: "))
print("factorial({0}) = {1}".format(n, fact(n)))

65
MEASURE COMPLEXITY - NUMBER OF MULTIPLICATIONS NEEDED

 T(n) = number of multiplications needed to


compute fact(n)
 T(0) = 0
 T(1) = T(0) + 1 = 1
 T(2) = T(1) + 1 = 2
 T(3) = T(2) + 1 = 3
 T(4) = T(3) + 1 = 4

66
METHOD OF BACKWARD SUBSTITUTIONS

 For the general case, we have


𝑇 𝑛 =𝑇 𝑛−1 +1
 The base case is
𝑇 0 =0
 Using the method of backward substitutions, we have
𝑇 𝑛 =𝑇 𝑛−1 +1= 𝑇 𝑛−2 +1 +1=𝑇 𝑛−2 +2
 Continuing this step, we obtain
𝑇(𝑛) = 𝑇(𝑛 − 𝑛) + 𝑛 = 𝑇(0) + 𝑛 = 𝑛
 Time efficiency of the recursive algorithm is of O(n)

67
ANALYSIS OF RECURSIVE ALGORITHMS

1. Decide on parameter n indicating input size


2. Identify algorithm’s basic operation
3. Determine the worst case for input of size n
4. Set up a recurrence relation with an appropriate initial condition
describing the number of times the basic operation is executed
5. Solve the recurrence by backward substitutions or other
methods

68
EXAMPLE: REVERSING AN ARRAY def ReverseArray(A, i, j):
if i < j:
temp = A[i]
A[i] = A[j] Swapping
Operation
A[j] = temp
ReverseArray(A, i+1, j-1)

A = [5, 3, 2, 6]
print("Original array: ", A)
first = 0
last = len(A) - 1
ReverseArray(A, first, last)
print("Reverse array: ", A)

69
TIME ANALYSIS FOR THE REVERSE ARRAY ALGORITHM

Let T(n) be the number of swapping operations needed to reverse


the elements of an array of size n. We also have T(0) = 0.

=…

70
RECURSIVE ALGORITHM MAY BE INEFFICIENT
 One should be careful with recursive algorithms as their conciseness, clarity and simplicity may
hide their inefficiency.
 Recall that the Fibonacci numbers are defined recursively: 𝑓𝑛 = 𝑓𝑛−1 + 𝑓𝑛−2 with 𝑓0 = 0 and
𝑓1 = 1.
 We have shown that an iterative algorithm (𝑓2 , 𝑓3 , 𝑓4 , … , 𝑓𝑛 ) for the Fibonacci numbers takes
(𝑛 − 1) steps. With a large value of 𝑛, it is roughly proportional to 𝑛. Hence, the running time
is of O(n).
 The recursive version looks simple but it is much time-consuming. In fact, the total number of
calls grows exponentially

71
BASIC DATA STRUCTURE: ARRAY

 A group of data elements stored in contiguous


memory.
 Advantage: Instant access to any element in the
array (i.e., it is just as easy to retrieve the value of
the first element as any other).
 Disadvantages: (1) Hard to insert new elements
in the middle of the array; (2) Deletion may be
time consuming.

72
head

BASIC DATA STRUCTURE: LINKED LIST

 Nodes are stored in memory locations that are dynamically allocated


 Each node of a linked list is composed of two parts: data part and next part
 Data part is used to store a data value
 Next part is used to hold the address (i.e., pointer) of the next node in the
list
 There is a pointer, called head, pointing to the starting of the linked list
 Advantages: The size of a linked list can be changed dynamically. New
nodes can be inserted
 Disadvantage: You do not have a quick access to members of a linked list
73
EXAMPLE: LINKED LIST

node node node

Null / None
head

74
LINKED LIST: INSERTION AND DELETION

Original linked list

Insertion

Deletion
75
ABSTRACT DATA TYPES (ADT)

 Some data structures are described abstractly in terms of the operations on


the data items but their detailed implementations are not specified
 ADT consists of functions that operate on the data
 Only the behavior of the ADT functions is specified
 The implementations of the ADT functions are not specified
 Examples: stacks and queues

76
STACKS

top
 Stack is an ADT in which an item can only be inserted
and removed from one end (the top).
 It follows the last-in-first-out (LIFO) strategy
 Applications: Page-visited history in a Web browser and
undo sequence in a text editor
LIFO

77
MAIN FUNCTIONS OF STACK ADT

 Stack( ): Make an empty stack.


 empty( ): Return true if the stack is empty; otherwise, return false.
 push(val): Add the item val to the top of the stack.
 pop( ): Remove the top (most recently added) item from the stack and the
deleted value is returned.
 top( ): Return the item most recently added to the stack, but do not remove it.

78
IMPLEMENTING STACK USING ARRAY

 A simple way of implementing a stack is to use an array


 We add elements from left to right
 A variable t keeps track of the index of the top element
 When an item is pushed onto the stack, we increment t (to 𝑡 = 𝑡 + 1) and
put the item in the cell at the new position.
 When an item is popped off the stack, we decrement t (to 𝑡 = 𝑡 − 1)

79
EXAMPLE: OPERATIONS OF STACK S

S = Stack()

push(3) 3 3

push(5) 5 5
7

True
7
push(7) pop( )
5 5 80
EXAMPLE: ONE(S)
# Include 5 basic stack functions here
 This algorithm returns True if there is
def one(S):
exactly one element in the stack S. if (S.empty()):
Otherwise, it returns False. The code return False
uses the abstract data type stack. val = S.top()
 Before and after issuing the function S.pop()
flag = S.empty()
one(S), the content of the stack S is the
S.push(val)
same. return flag
 It makes use of the 5 basic functions of
the ADT stack to complete the task. S = Stack()
S.push(1)
S.push(2)
S.pop()
print(one(S)) # True
81
QUEUES
front rear

 Insertions are at the rear of the queue and removals are at the front of the
queue
 Insertion (enqueue) and deletion (dequeue) follow the first-in first-out (FIFO)
scheme
 Applications: waiting lines at banks; access to shared resources (e.g.; printer);

82
MAIN FUNCTIONS OF QUEUE ADT

 Queue( ): Make an empty queue.


 empty( ): Return True if the queue is empty; otherwise, return False.
 enqueue(val): Add the item val to the rear of the queue.
 dequeue( ): Remove the item from the front (least recently added) of the
queue. The deleted value is returned.
 front( ): Return the item from the front of the queue, but do not remove it.

83
EXAMPLE: OPERATIONS OF QUEUE Q

Q = Queue()

True

84
IMPLEMENTING QUEUE USING ARRAY (1)

 A queue can be implemented using an array.


 Items are added at the rear and deleted from the front.
 We need two variables, r and f, to track the indexes of the rear and front of the
queue. An empty queue has both r and f equal to -1.
 When an item is added to an empty queue, we set r and f to 0 and put the
item in the cell 0.

85
IMPLEMENTING QUEUE USING ARRAY (2)

 When an item is added to a nonempty queue, we increment r and put the item
in the cell r
 After an item is removed from a nonempty queue, we increment 𝑓
 If 𝑓 = 𝑟, there is only one item in the queue. Any deletion will result in an
empty queue. (Set 𝑓 = 𝑟 = −1)

86
WRAPPED-AROUND FEATURES FOR QUEUES
 When using an array of fixed size to implement a queue, the queue is treated
in a circular fashion.
 If r is the index of the last cell in the array, we “wrap around” by setting r = 0
when adding an item
 When an item is deleted at the front, increment f. If f is the index of the last
cell in the array, we “wrap around” by setting f = 0.

87
EXAMPLE: QUEUE (1)

q = Queue()

88
EXAMPLE: QUEUE (2)

q.dequeue()

q.dequeue() q.dequeue()

= -1
= -1

89
WHAT IS A TREE?

 In computer science, a tree is an


abstract model of a hierarchical
structure
 A tree consists of nodes with a
parent-child relation
 Applications: Organization charts,
Table of Contents

90
TREES: TERMINOLOGY (1)

91
TREES: TERMINOLOGY (2)
This is a general rooted tree
 Root: node without parent (A)
 Internal node: node with at least one child (A, B, C, F)
 External node (or leaf): node without children (E, I, J,
K, G, H, D)
 Ancestors of a node: parent, grandparent, grand
grand-grandparent, etc.
 Depth of a node: number of ancestors
 Height of a tree: maximum depth of any node (e.g., 3)
 Degree : The number of children at a node
 Subtree: tree consisting of a node and its
descendants

92
BINARY TREES

 A binary tree is a rooted tree in which each node


has no children, one child, or two children.
 If a node has one child, that child is designated
as either a left child or a right child (but not
both).
 If a node has two children, one child is
designated a left child and the other a right child.
 When a binary tree is drawn, a left child is drawn
to the left and a right child is drawn to the right.

93
EXAMPLE: HEIGHT OF BINARY TREE

94
UNDERSTANDING THE RECURSIVE NATURE OF TREES

95
STRUCTURE OF A NODE
BINARY TREE TRAVERSALS

 To traverse a binary tree is to visit each node in the tree in some prescribed
order.
 Depending on the application, “visit” may be interpreted in various ways.
 For example, if we want to print the data in each node in a binary tree, we
would interpret “visit” as “print the data.”
 The three most common traversal orders are preorder, inorder, and postorder.
Each one is easily defined recursively.

97
PREORDER TRAVERSAL
Preorder traversal of a binary tree rooted at root is defined by the rules:

98
EXAMPLE: PREORDER TRAVERSAL

99
PREORDER ALGORITHM

# Preorder Traversal
# Root -> Left ->Right
def Preorder(self, root):
res = [] # At first, result is empty
if root: # if root is not empty
res.append(root.data) # read root.data
res = res + self.Preorder(root.left)
res = res + self.Preorder(root.right)
return res

100
INORDER TRAVERSAL
Inorder traversal of a binary tree rooted at root is defined by the rules:

101
EXAMPLE: INORDER TRAVERSAL

# Inorder Traversal
# Left -> Root -> Right
def Inorder(self, root):
res = [] # At first, result is empty
if root: # if root is not empty
res = self.Inorder(root.left)
or None
res.append(root.data) # read root.data
res = res + self.Ineorder(root.right)
or None
or None return res

res = [2, 4, 1, 6, 5, 7, 3]

102
POSTORDER TRAVERSAL
Postorder traversal of a binary tree rooted at root is defined by the rules:

103
EXAMPLE: POSTORDER TRAVERSAL

# Postorder Traversal
# Left -> Right -> Root
def Postorder(self, root):
res = [] # At first, result is empty
if root: # if root is not empty
res = self.Postorder(root.left)
res = res + self.Postorder(root.right)
res.append(root.data) # read root.data
return res

res = [4, 2, 6, 7, 5, 3, 1]
104
BINARY SEARCH TREES

105
EXAMPLE: BUILDING A BINARY SEARCH TREE

106
BINARY HEAP

107
STRUCTURAL PROPERTY OF HEAPS

108
ORDER PROPERTY OF HEAPS

109
A BINARY MAXHEAP

110
REPRESENTING A HEAP USING AN ARRAY

111
MAXHEAP IS WEAKLY SORTED

112
WEAKLY SORTED

113
MAINTAINING A MAXHEAP: SIFTDOWN

114
EXAMPLE: SIFTDOWN ALGORITHM (1)

115
EXAMPLE: SIFTDOWN ALGORITHM (2)

116
EXAMPLE: SIFTDOWN ALGORITHM (3)

117
EXAMPLE: SIFTDOWN ALGORITHM (4)

118
HOW TO MAKE A MAXHEAP?
 Given an array, how to turn it into a maxheap?
 Idea: why not make use of siftdown?
 But siftdown only works for array that looks like

maxheap maxheap

119
IDEA OF MAKING A MAXHEAP (1)

 Idea: apply siftdown starting near the leaves:

None is maxheap!
120
IDEA OF MAKING A MAXHEAP (2)

 Idea: apply siftdown starting near the leaves:

400

18

121
HEAPIFY: MAKING A MAXHEAP (1)
 The problem of organizing the data into a maxheap or minheap is called
𝒏
heapify, starting from index = down to index = 1.
𝟐

122
HEAPIFY: MAKING A MAXHEAP (2)
 The problem of organizing the data into a maxheap or minheap is called
heapify.

123
HEAPIFY: MAKING A MAXHEAP (3)
 The problem of organizing the data into a maxheap or minheap is called
heapify.

124

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy