IE2108 Part B (LKH) For Wks 4&5
IE2108 Part B (LKH) For Wks 4&5
61
ITERATIVE METHOD VS. RECURSIVE ALGORITHM
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?
63
EXAMPLE: FACTORIAL FUNCTION
Given that
𝑛! = 1 · 2 · 3 · ··· · 𝑛 − 1 ⋅ 𝑛
0! = 1 by definition Base 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
66
METHOD OF BACKWARD SUBSTITUTIONS
67
ANALYSIS OF RECURSIVE ALGORITHMS
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
=…
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
72
head
Null / None
head
74
LINKED LIST: INSERTION AND DELETION
Insertion
Deletion
75
ABSTRACT DATA TYPES (ADT)
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
78
IMPLEMENTING STACK USING ARRAY
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
83
EXAMPLE: OPERATIONS OF QUEUE Q
Q = Queue()
True
84
IMPLEMENTING QUEUE USING ARRAY (1)
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?
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
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)
None is maxheap!
120
IDEA OF MAKING A MAXHEAP (2)
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