0% found this document useful (0 votes)
27 views28 pages

CMPT125 Lecture22

Uploaded by

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

CMPT125 Lecture22

Uploaded by

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

CMPT 125

Introduction to Computing Science


and Programming II

Lecture 22
Emails
• I think I replied to all emails about lab exam and assignments
• If not, please let me know

• Sorry about the delay


Final exam
• Tuesday, December 13, 12:00-15:00. Location: Images Theatre
• Same format as the midterm and previous exams
• The exam is pen and paper
• Closed books, no cheat sheets, no calculators
• Please bring your student IDs.
• For previous exams look at the course homepage
https://www.cs.sfu.ca/~ishinkar/teaching/fall22/cmpt125/exams.html

• The material includes everything learned.


• Solve all practice problems on piazza, leetcode, google for “intro to CS in
C“.
Course Evaluations
• Course Evaluations Are Now Open
• Your written feedback will be appreciated very much

• You can also leave feedback on ratemyprofessors.com


Big-O notation
Q: Let f(n) = 13+23+33+…n3. Prove that f(n) = O(n4)
Proof: Need to show that there is a constant c such that f(n) <= cn 4 for
all n>1.
• We’ll show that f(n)<=n4 (i.e., we take c=1).
• Indeed, there are n terms, each <= n 3.
• Therefore,
• f(n) = 13+23+33+… (n-1)3 + n3 <= n3+ n3+… n3 = n*n3= n4
Fact: n4 is the tight answer.
Proof: f(n) > (n/2)3 + (n/2 + 1)3 + (n/2 + 2)3 + … + n3
> (n/2) * (n/2)3 = n4/16
Big-O notation
Q: write a function that gets n, and has running time
f(n) = 13+23+33+…n3.

foo(int n)
for i=1…n
for j=1…i
for k=1…i
for l=1…i
print(j+k+l)
Big-O notation
Q: T(n) = T(n/2) + n, and T(1)=1. Prove that T(n) = O(n)

Proof: Let’s prove that T(n)<=2n


Let’s suppose that n is a power of 2
T(n) = T(n/2) + n
= (T(n/4) + n/2) + n = T(n/4) + (n/2+n)
= T(n/8) + (n/4+n/2+n)
= T(n/16) + (n/8+n/4+n/2+n)
... = T(2) + (4+8…n/2+n) = T(1) + (2+ 4+8…n/2+n)
= (1+1/2+1/4+1/8+1/16…)*n < 2n
Big-O notation
Q: Write bar(n) with running time T(n) = T(n/2) + n, and T(1)=1.

bar(8) bar(n)
12345678 if n==0
return
1234 for i = 1..n
print i
12 bar(n/2)
1
Big-O notation
Consider the following function.
int f (int n) {
int sum = 0, i, j;
for (i=0; i<n; i++)
for (j=1; j<i; j=j*2)
sum += 1;
return sum;
}
Prove that the running time is O(n log(n))

Proof: We have n iterations of the outer for loop


For each outer iteration i=0..n-1 we have O(log(i)) < log(n) inner iterations.
So the total running time is O(# outer iterations) * O(log(n) = O(n log(n))

Remark: the O(n log(n)) in the tight answer: Look at the last n/2 iterations: i=n/2…n-1
In each them the inner loop makes > log(n/2) = log(n)-1>log(n)/2 steps
 sum>(n/2)*(log(n)/2) > n log(n)/4
Big-O notation
Consider the following function.
int f5 (int n) {
int sum = 0, i, j;
for (i=1; i<n; i=i*2)
for (j=0; j<i; j++)
sum += 1;
return sum;
}
Prove that the running time is O(n)
Proof: For each outer iteration we have i inner iterations.

The total running time is 1+2+4+8+16+…+n/2+n = (1+1/2+1/4+1/8…)n< 2n = O(n)


There are log(n) terms, but the sum is still < 2n
Big-O notation
Consider the following function.
int f5 (int n) {
int sum = 0, i;
for (i=2; i*i<n; i=i+1)
sum += 1;
return sum;
}
Prove that the running time is O(√n)

Proof: We iterate ii+1 until i*i>=n. This happens when i>=√n


Therefore, there are √n iterations.
Big-O notation
int foo(int n) {
if (n>0) {
int i, sum = 0;
for(i=0; sum<n ; i++) // note the condition is sum < n
sum = sum+i;
return i+foo(n-1);
}
return 0;
}
The running time is: T(n) = T(n-1) + O(n0.5)
= O(sqrt(n) + sqrt(n-1) + sqrt(n-2)…)<n1.5 = sqrt ( n3 )

- Recursion - T(n-1)
- For loop – definitely less than n. But what is the correct answer?
After k iterations sum=1+2+3…+k~k2/2
and we stop when sum>=n  k2/2>=n  k>=sqrt(2n)
Merge sort
Q: Consider the MergeSort we saw in class with O(n) time merge procedure.
What is the running time of MergeSort on a sorted array of length n?
Use big-O notation to state your answer.

Answer: The running time is O(n log(n)) on sorted arrays of length n.


Proof:
• The recursive calls do not depend on the values in the array,
• For an array of length n we make 2 recursive calls on subarrays of size n/2.
• For the merge procedure we merge the two halves, which takes O(n) time.
• Therefore, the total runtime is T(n) = 2T(n/2) + O(n) = O(n log(n))

Can make it O(n) on sorted arrays by checking first if the input is sorted in O(n) time

T(n) = O(n) + 2T(n/2) + O(n)


Get level k of a binary tree
Write an algorithm that gets a Binary Tree a number k and returns all values
at level k. What is the running time of your algorithm?

The question has several aspects:


• How to solve the problem algorithmically?
• What is the running time?
• How should we represent the output?
Get level k of a binary tree
Write an algorithm that gets a Binary Tree a number k and returns all
values at level k. What is the running time of your algorithm?

get_level_k(BTnode_t* root, k):


1. If root == NULL return EMPTY
2. If k==0 What is the running time?
O(size of tree) – not tight if k is small
1. Return root O(2k) – better answer
3. Else O(size of the tree up to level k)

1. L = get_level_k(root->left, k-1)
2. R = get_level_k(root->right , k-1)
3. Return L+R
Get level k of a binary tree
Write an algorithm that gets a Binary Tree a number k and returns all values
at level k. What is the running time of your algorithm?

1) How should we return the output?


int get_level_k(Btnode_t* root, int k, int* output) - returns length of the output

2) Define struct array_with_size {...}


array_with_size* get_level_k(Btnode_t* root, int k)

3) LL_t* get_level_k(Btnode_t* root, int k)


Depth of a tree
Compute depth iteratively. (Hint: use BFS)

BreadthFirstSearch(root):
q = create queue of nodes 10
Print 10
q.enqueue(root)
5 21
while q is not empty:
Print 5
21 1 7
node = q.dequeue() Print 21
1 7 16 25
printf(node->value) Print 1
if (node->left != NULL) 7 16 25
Print 7
q.enqueue(node->left)
16 25
Print 16
if (node->right != NULL) 25
Print 25
q.enqueue(node->right)
Depth of a tree
Compute depth iteratively. (Hint: use BFS)

BreadthFirstSearch(root):
q = create queue of nodes
Modify the queue to hold pairs
q.enqueue(root)
while q is not empty: (node, depth)
node = q.dequeue() - In the beginning add (root,0)
printf(node->value)
if (node->left != NULL)
- In each iteration get (node, i)
q.enqueue(node->left)
And add (node->child, i+1)
if (node->right != NULL)
q.enqueue(node->right)
Binary Search Trees
• Example 1:
• A binary search tree can be balanced
Binary Search Trees
Example 2:
binary search tree can be
very skinny / unbalanced
Not a Binary Search Tree
Not a Binary Search Tree
Remove node with no children
Remove (BST_t* tree, BTnode_t* node):
if (tree-> root == node) 4
tree->root = NULL;
else 2 6
if (node ->parent->left == node)
set_left_child(node->parent, NULL)
1 3 5 7
else // node ->parent->right == node
set_right_child(node->parent, NULL)
free(node)
remove( 3 )
Remove node with one child
Remove (BST_t* tree, BTnode_t* node): 4

child = getChild(node); 3 5
if (tree->root == node)
7
root = child; 2

else 6
1
if (node->parent->left == node) remove( 3 )
set_left_child(node->parent, child);
remove( 7` )
else // node->parent->right == node
set_right_child(node->parent, child);
free(node)
Remove node with two children
remove( 4 )
Remove (BST_t* tree, BTnode_t* node)
next = find successor of node in the tree; 4
// next has ≤1 child
node->value = next->value; 2 6

Remove (tree, next);


1 3 5 7

Successor of 4 is 5
BST 1
Create a Binary Search Tree from the following list of insertions:
List: 4, 2, 8, 1, 3 , 6, 5, 9, 10, 7
4

Remove 5 from the tree 2 8


Remove 9 from the tree
Remove 4 from the tree 1 3 6 9

5 7 10
Queues
Write the states of the queue for this execution

1. queue_t* q = queue_create(); []
2. enqueue(q, 1); <- [1] <-
3. enqueue(q, 2); [1,2]
4. enqueue(q, 3); [1,2,3]
5. enqueue(q, 4); [1,2,3,4]
6. dequeue(q); [2,3,4]
7. enqueue(q, 5); [2,3,4,5]
8. enqueue(q, 1); [2,3,4,5,1]
9. dequeue(q); [3,4,5,1]
10. enqueue(q, 1); [3,4,5,1,1]
11. enqueue(q, 3); [3,4,5,1,1,3]
12. dequeue(q); [4,5,1,1,3]
Questions?
Comments?

You might also like