BNF - Backus-Naur form ====================== Define syntax for boolean logic: Sentence (well-formed sentence - WFS) is 1) A literal: Examples: A B C or 2) if S1 and S2 are WFS then ( (S1) & (S2) ) ( (S1) | (S2) ) ....... are also WFS. A B ( (A) & (B) ) ( (B) | (( (A) & (B) )) ) ( (( (A) & (B) )) & (( (B) | (( (A) & (B) )) )) ) Or in short: Sentence is literal sentence & sentence sentence | sentence Examples: A B A & B A | B A & B & A | B A & B | A | B A & B & A | B & A | B Similar recurrence relation, or recurrence, or recursive formula in mathematics: Example: Fibonacci numbers: F(0) = 1, F(1) = 1 F(n) = F(n-2)+F(n-1) Example (using 2 arguments): Binomial coefficients: b(n,0) = b(n,n) = 1 for all n b(n,k) = b(n-1,k-1)+b(n-1,k) It can be shown that b(n,m) = n! / ( m! (n-m)! ). I.e. recursive definition can be transformed into closed form Example: Ackermann function: A(0,n) = n+1 A(m,0) = A(m-1,1) A(m,n) = A(m-1,A(m,n-1)) In computer science =================== Recursive functions: -------------------- Function that calls inteslf (possibly through a call to another function). Example: int f ( int n ) { // base case 0 if ( n == 0 ) return 0; // lookup return f(n-1) + 2*n-1; } By math induction: 1) f(0) = 0 2) { f(n) = n^2 } => { f(n+1) = (n+1)^2 } for all n : f(n) = n^2 ============================= int f ( int n ) { // base case 0 if ( n == 0 || n == 1 ) return 1; // lookup // general case return f(n-1) + f(n-2); } Fib: 1 1 2 3 5 8 13 .. Closed form? ============================= insert in the end of a singly linked list assume non-empty void push_back( Node * p, Node const& n) { // base if ( p->next == nullptr ) { p->next = &n; return; } push_back( p->next, n ); } ============================= insert in the end of linked list empty is allowed void push_back( Node ** p, Node const& n) { // empty list if ( !*p ) { *p = &n; return; } if ( (*p)->next == nullptr ) { (*p)->next = &n; return; } push_back( &((*p)->next), n ); } // using references void push_back( Node *& p, Node const& n) { // empty list if ( !p ) { p = &n; return; } if ( p->next == nullptr ) { p->next = &n; return; } push_back( p->next, n ); } //second version more efficient - only 1 check for empty list void push_back( Node ** p, Node const& n) { if ( *p == nullptr ) { *p = &n; } else { push_back_aux( *p, n ); } } void push_back_aux( Node * p, Node const& n) { // base if ( p->next == nullptr ) { // easy fix p->next = &n; return; } push_back_aux( p->next, n ); } ================================== find value in unsorted array int find( int* a, int size, int val ) // position { //base if ( size == 1 ) return ( a[0] == val ) ? 0 : -1; // general case int pos1 = find( a, size/2, val ); if ( pos1 != -1 ) return pos1; int pos2 = find( a+size/2, size - size/2, val ); if ( pos2 != -1 ) return pos2+size/2; return -1; } run-time = O(size) ================================== // assume sorted array int find( int* a, int size, int val ) // position //base if ( size == 1 ) return ( a[0] == val ) ? 0 : -1; if ( a[size/2] > val ) { int pos1 = find( a, size/2, val ); if ( pos1 != -1 ) return pos1; } else { int pos2 = find( a+size/2, size-size/2, val ); if ( pos2 != -1 ) return pos2+size/2; } return -1; } run-time = log_2 size ========================================= iterative - > recursive while ( C ) int foo( int i ) { { if ( !C ) return res; --i; //--i calc calc; } return foo( i-1 ); // tail recursion return res; } tail recursion recursive - > iterative //print right to left - linear recursion (not tail) void print( char* str ) { if ( *str == 0 ) return; print( str+1 ); std::cout << *str; } Stack: +-V-------+ time 1 |RC cout A| +---------+ +-V-------++-V-------+ time 2 |RC cout ||RC cout B| +---------++---------+ +-V-------++-V-------++--V------+ time 3 |RC cout ||RC cout || RC coutC| +---------++---------++---------+ +-V-------++-V-------++--V------++-V-------+ time 4 |RC cout ||RC cout || RC cout ||RC cout D| +---------++---------++---------++---------+ +-V-------++-V-------++--V------++-V-------++----V----+ time 5 |RC cout ||RC cout || RC cout ||RC cout ||base case| +---------++---------++---------++---------++---------+ +-V-------++-V-------++--V------++---V-----+ time 6 |RC cout ||RC cout || RC cout ||RC cout D| +---------++---------++---------++---------+ +-V-------++-V-------++----V----+ time 7 |RC cout ||RC cout || RC coutC| +---------++---------++---------+ +-V-------++---V-----+ time 8 |RC cout ||RC cout B| +---------++---------+ +---V-----+ time 9 |RC cout A| +---------+ // right to left - rewrite above as tail recursion void print( char* str, std::string result ) { if ( *str == nullptr ) { std::cout << result; return; } print( str+1, *str + result ); // new argument to maintain partial final result // each recursive call updates it and passes to the next } =========================================== // linear recursion long sum(long n) { if ( n==1 ) return 1; return n+sum(n-1); } void sum_aux(long n, long & result) { if (n==0) return; sum_aux(n-1,result+=n); } long sum(long n) { long result = 0; sum_aux(n,result); return result; } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% print all possible pairs of 0s and 1s for ( int i=0; i < 2; ++i ) { for ( int j=0; j < 2; ++j ) { std::cout << i << " " << j << std::endl; } } print all possible triples of 0s and 1s and 2s for ( int i=0; i < 3; ++i ) { for ( int j=0; j < 3; ++j ) { for ( int k=0; k < 3; ++k ) { std::cout << i << " " << j << << " " << k << std::endl; } } } print all possible m-tuples of 0s and 1s and ..... m-1's =============================================== // non-constant number of nested loops //g++ -std=c++11 multi-loop.cpp #include #include void rec_aux( int d, int max, std::vector & str ) { if ( d == max ) { for ( auto const& s: str ) { std::cout << s << " "; } std::cout << std::endl; return; } for ( int i=0; i < max; ++i ) { str.push_back( i ); rec_aux( d+1, max, str ); str.pop_back( ); } } void all_tuples( int n ) { std::vector str; rec_aux( 0, m, str ) } ================================================== // same as above, but vector is copied, rather than passed // by reference. Notice that pop_back is commented out void rec_aux( int d, int max, std::vector str ) { if ( d == max ) { for ( auto const& s: str ) { std::cout << s << " "; } std::cout << std::endl; return; } for ( int i=0; i < max; ++i ) { str.push_back( i ); rec_aux( d+1, max, std::vector( str )+= "i" ); //str.pop_back( ); } } void all_tuples( int n ) { std::vector str; rec_aux( 0, m, str ) }