Use the memoization optimization algorithm in C/C ++
Take the calculation of common Fibonacci series as an example:
# Include <stdio. h> # define COUNT_TIMES 10 int fib (int n) {if (n = 0 | n = 1) {return 1;} else {return fib (n-2) + fib (n-1) ;}} int main () {int I; for (I = 0; I <COUNT_TIMES; I ++) printf ("fib % d \ n", fib (I ));}
Output:
Fib 1
Fib 1
Fib 2
Fib 3
Fib 5
Fib 8
Fib 13
Fib 21
Fib 34
Fib 55
In fact, let's take a look at the number of computations.
# Include <stdio. h ># define COUNT_TIMES 10 int count; int fib (int n) {if (n = 0 | n = 1) {return 1 ;}else {count ++; return fib (n-2) + fib (n-1) ;}} int main () {int I, * mem; for (I = 0; I <COUNT_TIMES; I ++) {printf ("n % d result % 2d calculation times % d \ n", I, fib (I), count); count = 0 ;}}
Result:
N 0 Result 1 calculation count 0
N 1 result 1 calculation count 0
N 2 Result 2 calculation count 1
N 3 result 3 calculation count 2
N 4 result 5 calculation times 4
N 5 Results 8 computing times 7
N 6 result 13 calculation times 12
N 7 Result 21 calculation times 20
N 8 Result 34 calculation count 33
N 9 result 55 calculation times 54
We found that the actual number of computations is the same as the result. The calculation of the Fibonacci number of n is fib (n)-1. Think about it.
So let's use memoization to optimize it:
# Include <stdio. h> # include <stdlib. h> # define COUNT_TIMES 10 int count; int fib (int n, int * mem) {// if no result is cached, it is calculated, add the result to the cache. if (mem [n] =-1) {mem [n] = fib (n-1, mem) + fib (n-2, mem); // count ++;} // return the cache result return mem [n];} int main () {int I, j, * mem; for (I = 0; I <COUNT_TIMES; I ++) {// request a piece of memory to cache the result mem = (int *) malloc (sizeof (int) * COUNT_TIMES ); // initialize the result mem [0] = mem [1] = 1; for (j = 2; j <COUNT_TIMES; j ++) mem [j] =-1; // call printf ("n % d result % 2d calculation times % d \ n", I, fib (I, mem), count); count = 0; // zero the number of computations (mem); // release the memory used for caching }}
After optimization, we can find that the time complexity is easily changed to O (n).
N 0 Result 1 calculation count 0
N 1 result 1 calculation count 0
N 2 Result 2 calculation count 1
N 3 result 3 calculation count 2
N 4 result 5 calculation count 3
N 5 Results 8 calculation times 4
N 6 result 13 calculation count 5
N 7 Result 21 calculation times 6
N 8 Result 34 calculation times 7
N 9 results 55 calculation times 8
After optimization, when n = 15, the speed is about 1000 times that of the original version, and when n = 27, the speed is about 10000 times that of the original version. It should be said that the larger the calculation workload of repeated computation, the more obvious the effect obtained by using memoization. However, in actual applications, we should consider whether the memory consumption is worthwhile, that is, a cost-effectiveness.
Finally, remove the comments and simply encapsulate them.
# Include <stdio. h> # include <stdlib. h> # define COUNT_TIMES 10 int * init_mem () {int I, * mem; mem = (int *) malloc (sizeof (int) * COUNT_TIMES ); mem [0] = mem [1] = 1; for (I = 2; I <COUNT_TIMES; I ++) mem [I] =-1; return mem ;} int fib (int n, int * mem) {if (mem [n] =-1) mem [n] = fib (n-1, mem) + fib (n-2, mem); return mem [n];} int main () {int I, * mem; for (I = 0; I <COUNT_TIMES; I ++) {mem = init_mem (); printf ("fib % d \ n", fib (I, mem); free (mem );}}
Use Memoization to avoid recurrence
Consider the issue of Fibonacci;
A simple recursive method can be used to solve the problem of Fibonacci:
Int fib (n) {if (n = 0 | n = 1) {return 1;} else {return fib (n-2) + fib (n-1 );}}
Note: Here, we consider the Fibonacci series starting from 1. Therefore, the series looks like ,...
Note: From the recursive tree, we calculate the fib (3) function twice and the fib (2) function three times. This is the repeated calculation of the same function. If n is very large, fib
This simple technology is called Memoization and can be used in recursion to increase the computing speed.
The code of the fibonacci function Memoization should look like the following:
Int calc_fib (int n) {int val [n], I; for (I = 0; I <= n; I ++) {val [I] =-1; // Value of the first n + 1 terms of the fibonacci terms set to-1} val [0] = 1; // Value of fib (0) is set to 1 val [1] = 1; // Value of fib (1) is set to 1 return fib (n, val);} int fib (int n, int * value) {if (value [n]! =-1) {return value [n]; // Using memoization} else {value [n] = fib (n-2, value) + fib (n-1, value); // Computing the fibonacci term} return value [n]; // Returning the value}
The red part of the code above does not know why it can be declared. Arrays in standard C and C ++ cannot be declared in that way. It may be extended using the compiler.
Below is what I wrote in C ++:
# Include <iostream> # include <algorithm> # include <iterator> using namespace std; int fib (int n, int val []) {if (val [n]! =-1) return val [n]; else {val [n] = fib (n-1, val) + fib (N-2, val); return val [n];} void cal_fib (int n) {int * val = new int [n + 1]; for (int I = 0; I <= n; I ++) val [I] =-1; val [0] = 0; val [1] = 1; fib (n, val); copy (val, val + n + 1, ostream_iterator <int> (cout, ""); cout <endl; delete [] val ;}int main () {for (int I = 3; I <= 15; I ++) cal_fib (I );}
The output result is as follows:
Optimize recursive calls using memoization in JS
I. Preface
Memoization: This word has been seen several times, and the impression in my mind is used to optimize recursive calls (I know, not only that). Even so, I still think that, it is not a method, but a thought or idea. Here we record a bit of existing understanding and will gradually increase...
II. Application
When I searched the internet, I found that most of them used the calculation of the ripple number as an example. I didn't make it special either:
// General code function fib (n) {if (n <2) {return n;} return fib (n-1) + fib (n-2 );}
Analysis: The execution efficiency of this code is very low. The reason is that you need to call the function repeatedly and there are a lot of repeated computations in each call. Obviously, the larger n, the more calls.
// The optimized code var mFib = function () {var cache = [1, 1]; // The first two values of the merge po number are 1 and 1 return function (m) {var len = cache. length, I = len; // if m is greater than the length of the cache, it indicates that the number of merge po S corresponding to m does not exist. if (m> len) needs to be calculated) {// when I is equal to m, the number of smoothing po s earlier than I has been calculated. You can directly use the for loop in some examples, however, while loops are faster. while (I <= m) {// The characteristics of the number of orders, the latter is equal to the sum of the first two numbers. // The results are cached, avoid re-computing cache [I] = cache [I-2] + cache [I-1]; I ++ ;}// when the number of merge polards exists, directly use return cache [m-1] ;}} ();
Analysis: the idea of this method is to cache the computed results, which can reduce a lot of repeated computations and improve the execution efficiency.