190 likes | 258 Views
CSc142 Algorithms and efficiency Week 7. Pete Bagnall bagnall@comp.lancs.ac.uk Elizabeth Phillips e.m.phillips@lancaster.ac.uk. Week 7 topics. Popular algorithms Factorial Fibonacci A coursework example. Maths: Factorial. n! is known as “n factorial” 0! = 1 1! = 1 2! = 2 x 1
E N D
CSc142Algorithms and efficiencyWeek 7 Pete Bagnall bagnall@comp.lancs.ac.uk Elizabeth Phillips e.m.phillips@lancaster.ac.uk
Week 7 topics Popular algorithms Factorial Fibonacci A coursework example
Maths: Factorial n! is known as “n factorial” 0! = 1 1! = 1 2! = 2 x 1 3! = 3 x 2 x 1 4! = 4 x 3 x 2 x 1 5! = … and so on. Generally n! = n x (n-1) x (n-2) x … x 3 x 2 x 1 How many ways can you order 3 things?
Permutations How many ways can you pick k objects from a set of n objects? Pick 3 objects from a set of 5 objects. perm(n, k) = fact(n) / fact(n-k) 2 letter permutations from C, A, T: CA, CT, AC, AT, TC, TA 5 x 4 x 3 x 2 x 1 5! n! nPk 5 x 4 x 3 = = = = 2 x 1 2! (n-k)!
Factorials - Simpson's Tile Puzzle You might ask: How many start positions are there? perm(9, 9) = 9! / 0! (0! = 1) = 9! = 9 x 8 x 7 x 6 x 5 x 4 x 3 x 2 x 1 = 362,880 Note that not all of these start positions can be reached from the finish positions.
A factorial function int factorial(int n) { if (n <= 1) { return 1; } else { return n * factorial(n - 1); } } A recursive function (it calls itself). Looks simple, with some hidden complexity! No initialisation? No loop?
Recursive factorial function int factorial(int n) { if (n <= 1) { return 1; } else { return n * factorial(n - 1); } } Call with factorial(3) if (3<=1); return 3 * factorial(3 - 1); if (2<=1); return 2 * factorial(2 - 1); if (1<=1); return 1;
Recursive factorial function Time for factorial(n) depends on depth of recursion - which depends on n. It’s O(N) int factorial(int n) { if (n <= 1) { return 1; } else { return n * factorial(n - 1); } } Executes ‘long’ branch (n - 1) times Executes the short branch once
What recursion hides Functions operate in a ‘context’ that defines where they were called from what arguments they received their local variables their return value This context is implemented as a stack frame. A stack frame is created on the stack when function is called. The stack frame is destroyed when function returns.
Function context in stack frame Calling code Creates stack frame Fills in return address and argument values. Jumps to start of function. Called code Fills in return value Jumps to return address Calling code Retrieves return value Destroys stack frame
Another O(N) factorial int iterativeFactorial(int n) { int result = 1; for (int i = 2; i <= n; i++) { result *= i; } return result; } No recursion, slightly more code. Appears to have worse secondary efficiency… But remember - method calls take time need to set up and tear down the stack frame
An O(1) factorial How many int factorials are there? We said n! rises fast. A Java int is 32 bits values from -2,147,483,648 to 2,147,483,647 (Java only has signed integers, unlike C, C++) 2,147,483,647 max +ve int 12! = 479,001,600 ok 13! = 6,227,020,800 not ok!
An O(1) factorial final static int INT_FACTORIAL[] = new int[] {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600}; int instantFactorial(int n) { return INT_FACTORIAL[n]; } Question: How many items in the array for the long version of this program?
Fibonacci The Fibonacci series is 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89… Fib(0) = 1 Fib(1) = 1 Fib(i) = Fib(i-1) + Fib(i-2) A recursive definition! int fib(int n) { if (n <= 1) { return 1; } else { return fib(n - 2) + fib(n - 1); }}
Fibonacci complexity 1 0 1 0 1 1 2 2 2 3 3 4 5 Not as straightforward as factorial Look at the number of times fib() is called… 0 1 fib(0) 1 fib(1) 1 fib(2) 3 fib(3) 5 fib(4) 9 fib(5) 15 Tfib(n) = Tfib(n-1) + Tfib(n-2) + 1 fib(n)
Fibonacci optimisations Fibonacci series soon produces very large numbers. fib(46) = 1,836,311,903 (getting close to limit of 32-bit int) fib(46) takes a long time to compute! O(Tfib(N)) Use iterative code like… It’s O(N)! int iterativeFib(int n) { int[] fib = new int[n + 1]; fib[0]=1; fib[1]=1; for (int i=2; i<=n; i++) { fib[i] = fib[i-1] + fib[i-2]; } return fib[n]; }
A coursework example Some code: int X(int[] Y) { int Z = 0; for (int i = 0; i < Y.length; i++) Z = Z + Y[i] / Y.length; return Z; } What does this function do? What is its time complexity O()? What optimisations can you make? Re-write the code. Can you improve primary efficiency of X? Why not? X() has a serious problem which may be fixed in your version. What is the problem? What potential error have you introduced?
The last slide We've covered: Two famous recursive algorithms Factorial Fibonacci An example coursework question Next week: Popular algorithms `Styles' of algorithm Coursework examples Some questions from the notes