Queues Array resizing and recursion and recursion October
Queues Array resizing and. . . recursion and recursion October 05, 2018 Cinda Heeren / Geoffrey Tien 1
Announcements • MT 1 – grading in progress! • HW 2 – under construction, release very soon! – suggestion for extra weekend due date has been heard and is very likely • There will be no lab activities next week! – But regular sessions will be staffed as office hours October 05, 2018 Cinda Heeren / Geoffrey Tien 2
Queue operations • A queue should implement at least the first two of these operations: – enqueue – insert item at the back of the queue – dequeue – remove an item from the front – peek – return the item at the front of the queue without removing it – is. Empty – check if the queue does not contain any items • Like stacks, it is assumed that these operations will be implemented efficiently – That is, in constant time October 05, 2018 Cinda Heeren / Geoffrey Tien 3
Queue implementation Using an array • Consider using an array as the underlying structure for a queue, we could – Make the back of the queue the current size of the array, much like the stack implementation – Initially make the front of the queue index 0 – Inserting an item is easy • What to do when items are removed? – Either move all remaining items down – slow – Or increment the front index – wastes space October 05, 2018 Cinda Heeren / Geoffrey Tien 4
Circular arrays • Trick: use a circular array to insert and remove items from a queue in constant time • The idea of a circular array is that the end of the array “wraps around” to the start of the array 7 0 6 0 1 2 3 4 5 6 7 1 2 5 4 October 05, 2018 Cinda Heeren / Geoffrey Tien 3 5
The modulo operator • The mod operator (%) calculates remainders: – 1%5 = 1, 2%5 = 2, 5%5 = 0, 8%5 = 3 • The mod operator can be used to calculate the front and back positions in a circular array – Thereby avoiding comparisons to the array size – The back of the queue is: • (front + num) % arrlength • where num is the number of items in the queue – After removing an item, the front of the queue is: • (front + 1) % arrlength October 05, 2018 Cinda Heeren / Geoffrey Tien Member attributes: int front; int arrlength; int* arr; int num; 6
Array queue example Queue q; q. enqueue(6); 0 01 front num 6 0 1 2 3 4 5 Insert item at (front + num) % queue. length, then increment num October 05, 2018 Cinda Heeren / Geoffrey Tien 7
Array queue example 210 345 q. enqueue(6); front num q. enqueue(4); q. enqueue(7); q. enqueue(3); q. enqueue(8); 6 4 7 3 8 0 1 2 3 4 Queue q; q. dequeue(); 5 Insert item at (front + num) % queue. length, then increment num Remove item at front, then decrement num and make front = (front + 1) % queue. length October 05, 2018 Cinda Heeren / Geoffrey Tien 8
Array queue example 2 543 q. enqueue(6); front num q. enqueue(4); q. enqueue(7); q. enqueue(3); q. enqueue(8); 5 Queue q; q. dequeue(); q. enqueue(9); q. enqueue(5); 0 1 7 3 8 9 2 3 4 5 Insert item at (front + num) % queue. length, then increment num Remove item at front, then decrement num and make front = (front + 1) % queue. length Need to check that the back of the queue does not overtake the front October 05, 2018 Cinda Heeren / Geoffrey Tien 9
Array queue resizing • Suppose we have an array-based queue and we have performed some enqueue and dequeue operations – Then we perform more enqueues to fill the array – How should we resize the array to allow for more enqueue operations? 12 5 76 33 2 41 ? ? front ? October 05, 2018 ? ? ? Cinda Heeren / Geoffrey Tien ? ? 10
Queue implementation Using a Linked List • Removing items from the front of the queue is straightforward • Items should be inserted at the back of the queue in constant time – So we must avoid traversing through the list – Use a second node pointer to keep track of the node at the back of the queue • Requires a little extra administration October 05, 2018 Cinda Heeren / Geoffrey Tien Member attributes: Node* front; Node* back; int num; 11
List queue example Queue q; q. enqueue(6); q. enqueue(4); front 6 back 4 q. enqueue(7); q. enqueue(3); q. dequeue(); 7 3 October 05, 2018 Cinda Heeren / Geoffrey Tien 12
Exercise Shallow Copy, Deep Copy • Given a Queue class implemented with a (dynamic) circular array of 8 int elements and an integer size member, the following block of code is executed: Queue q. A; q. A. Enqueue(34); q. A. Enqueue(29); q. A. Enqueue(11); q. A. Dequeue(); q. A. Enqueue(47); q. A. Dequeue(); What will be output as the contents of each queue q. A and q. B if: • q. B is created as a shallow copy of q. A? • q. B is created as a deep copy of q. B? Queue q. B = q. A; q. A. Enqueue(6); q. B. Enqueue(52); q. B. Dequeue(); q. A. Dequeue(); October 05, 2018 Cinda Heeren / Geoffrey Tien 13
Recursion October 05, 2018 Cinda Heeren / Geoffrey Tien 14
Rabbits!. . . and recursion • What happens when you put a pair of rabbits in a field? – More rabbits! • Let’s model the rabbit population, with a few assumptions: – Newly-born rabbits take one month to reach maturity and mate – Each pair of rabbits produces another pair of rabbits one month after mating – Rabbits never die October 05, 2018 Cinda Heeren / Geoffrey Tien 15
More rabbits. . . • How many rabbit pairs are there after 5 months? Month 1: start – 1 pair Month 2: first pair are now mature and mate – 1 pair Month 3: first pair give birth to a pair of babies – original pair + baby pair = 2 pairs Month 4: first pair give birth to another pair of babies, pair born in month 3 are now mature – 3 pairs October 05, 2018 1 2 3 4 5 6 1 1 2 3 5 8 Month 5: the 3 pairs from month 4, and two new pairs – 5 pairs Month 6: the 5 pairs from month 5, and three new pairs – 8 pairs And so on. . . Cinda Heeren / Geoffrey Tien 16
Fibonacci series • The nth number in the Fibonacci series, fib(n), is: – 0 if n = 0, and 1 if n = 1 – fib(n – 1) + fib(n – 2) for any n > 1 • e. g. what is fib(23) – Easy if we only knew fib(22) and fib(21) – The answer is fib(22) + fib(21) – What happens if we actually write a function to calculate Fibonacci numbers like this? October 05, 2018 Cinda Heeren / Geoffrey Tien 17
Calculating the Fibonacci series • Let’s write a function just like the formula • fib(n) = 0 if n = 0, 1 if n = 1, • otherwise fib(n) = fib(n – 1) + fib(n – 2) int fib(int n) { if (n <= 1) return max(0, n); else return fib(n-1) + fib(n-2); } October 05, 2018 Cinda Heeren / Geoffrey Tien The function calls itself 18
Recursive functions • The Fibonacci function is recursive – A recursive function calls itself – Each call to a recursive method results in a separate call to the method, with its own input • Recursive functions are just like other functions – The invocation (e. g. parameters, etc. ) is pushed onto the call stack – And removed from the call stack when the end of a method or a return statement is reached – Execution returns to the previous method call October 05, 2018 Cinda Heeren / Geoffrey Tien 19
Recursive function anatomy • Recursive functions do not use loops to repeat instructions – But use recursive calls, in if statements • Recursive functions consist of two or more cases, there must be at least one – Base case, and – Recursive case October 05, 2018 Cinda Heeren / Geoffrey Tien 20
Recursion cases • The base case is a smaller problem with a known solution – This problem’s solution must not be recursive • Otherwise the function may never terminate • There can be more than one base case – And base cases may be implicit • The recursive case is the same problem with smaller input – The recursive case must include a recursive function call – There can be more than one recursive case October 05, 2018 Cinda Heeren / Geoffrey Tien 21
Analysis of fib(5) int fib(int n) { if (n <= 1) return max(0, n); else return fib(n-1) + fib(n-2); } 5 fib(5) 2 3 fib(3) fib(4) 2 fib(3) 1 1 fib(1) 0 fib(0) October 05, 2018 1 fib(1) 1 1 fib(2) 0 fib(0) 1 fib(1) 0 fib(0) Later in the course we will explain how this is an extremely inefficient way to compute the Fibonacci series Cinda Heeren / Geoffrey Tien 22
Example Recursive linear search • Base cases – Target is found, or the end of the array is reached • Recursive case – Target not found, search subarray starting from next element // Recursive linear search int rec. Lin. Search(int arr[], int next, int sz, int x) { if (next >= sz) // end of array reached return -1; else if (x == arr[next]) // target found return next; else // not found, search from different starting index return rec. Lin. Search(arr, next + 1, sz, x); } October 05, 2018 Cinda Heeren / Geoffrey Tien 23
Readings for this lesson • Carrano & Henry – Chapter 13. 1 – 13. 2 (Queues) – Chapter 2 (Recursion) • Next class: – Carrano & Henry, Chapter 15. 1 (Trees) October 05, 2018 Cinda Heeren / Geoffrey Tien 24
- Slides: 24