Your Federal Quarterly Tax Payments are due April 15th Get Help Now >>

07 by malj

VIEWS: 12 PAGES: 18

									                                                Read §7.4
          7.Algorithm Efficiency
What to measure?
 Space utilization:     amount of memory required
Time efficiency:       amount of time required to
 process the data
Depends on many factors:
  • size of input
  • speed of machine
  • quality of source code
  • quality of compiler
These factors vary from one machine/compiler (platform)
 to another
 Count the number of times instructions are executed
So, measure computing time as
  T(n)     = computing time of an algorithm for input1 of
    Example: Calculating the Mean
/* Algorithm to find the mean of n real numbers.
   Receive: integer n >= 1 and an array x[0], . . . , x[n–1] of real
numbers
   Return: The mean of x[0], . . . , x[n–1]
----------------------------------------------------
------------------------------------*/
1. Initialize sum to 0.
2. Initialize index variable i to 0.
3. While i < n do the following:
4.    a. Add x[i] to sum.
5.    b. Increment i by 1.
6. Calculate and return mean = sum / n .

T(n) = ___________

                                                                 2
                Big Oh Notation
The computing time of an algorithm on input of size n,
T(n), is said to have order of magnitude f(n), written
T(n) is O(f(n))
if there is some ____________________ such that
    _____________ for all sufficiently ____________________ .
                                               f(n) is usually simple:
                                                     n, n2, n3, ...
Another way of saying this:                                2n
  The complexity of the algorithm is    O(f(n)).        1, log2n
                                                        n log2n
                                                       log2log2n
Example: For the Mean-Calculation Algorithm:
   T(n) is _________
Note that constants and multiplicative factors are
ignored.
                                                             3
               Worst-case Analysis
The arrangement of the input items may affect the computing
time.
How then to measure performance?
   best case – not very informative
   average - too difficult to calculate
   worst case - usual measure
/* Linear search of the list a[0], . . . , a[n – 1].
    Receive: An integer n an array of n elements and item
    Return: found = true and loc = position of item if the search is
       successful; otherwise, found is false. */
1. found = false.
2. loc = 0.
3. While (loc < n && !found )
4.     If item = a[loc] found = true              // item found
5.     Else              increment loc by 1 // keep searching
Worst case: Item not in the list: TL(n) is _______
                                                                   4
Average case (assume equal distribution of values) is ______
                       Binary Search
/* Binary search of the list a[0], . . . , a[n – 1] in which the items are
in
   ascending order.
   Receive: integer n and an array of n elements and item.
   Return: found = true and loc = position of item if the search
successful
               otherwise, found is false. */
1. found = false.
2. first = 0.
3. last = n – 1.
4. While (first < last && !found )
5.     Calculate loc = (first + last) / 2.
6.     If item < a[loc] then
7.          last = loc – 1.// search first half
8.     Else if item > a[loc] then
9.          first = loc + 1.       // search last half
10. Else
            found = true. // item found
                                                                       5
Worst case: Item not in the list:           TB(n) = ____________
                                                            Read §7.1, 7.3
                                                            Skim §7.2
                          Recursion
A very old idea, with its roots in mathematical induction. It always has:
   An anchor (or base or trivial) case
   An inductive case

So, a function is said to be defined recursively if its definition consists
of
   An ___________________________ in which the function’s value is
defined
       for one or more values of the parameters
   An ____________________________________in which the function’s
value
       (or action) for the current parameter values is defined in terms
of
       previously defined function values (or actions) and/or parameter
values.
 int Factorial(int n)
 { if (n < 2)
Example: Factorials
      return 1;
 Base case: 0! = 1
    else
      return n * Factorial(n
 Inductive case: n! = n*(n-1)! - 1);                               6
 }
       Computing times of recursive
                functions
Have to solve a recurrence relation.

// Towers of Hanoi
void Move(int n, char source, char destination, char spare)
{
if (n <= 1)              // anchor (base) case
    cout << "Move the top disk from " << source
          << " to " << destination << endl;
  else
  {                      // inductive case
     Move(n-1, source, spare, destination);
     Move(1, source, destination, spare);
     Move(n-1, spare, destination, source);
  }
}

                                                          7
T(n) = ____________
       Comments on Recursion
There are several common applications of recursion
where a corresponding iterative solution may not be
obvious or easy to develop. Classic examples of such
include Towers of Hanoi, path generation,
multidimensional searching and backtracking.

However, many common textbook examples of
recursion are tail-recursive, i.e. the last statement in
the recursive function is a recursive invocation.

Tail-recursive functions can be (much) more
efficiently written using a loop.


                                                       8
// Counting the number of digits in a positive integer
int F(unsigned n, int count)
{                                 // recursive, expensive!
  if (n < 10)
    return 1 + count;
  else
    return F(n/10, ++count);
                               }

int F(unsigned n)
{                                // iterative, cheaper
  int count = 0;
  while (n >= 10)
  {
    count++;
    n /= 10;
  }
  return count;
}

                                                             9
// Fibonacci numbers
int F(unsigned n)
{                                      // recursive, expensive!
  if (n < 3)
    return 1;
  else                                       Recursive:
    return F(n –1) + F(n - 2);
                                   }
                                             O(_______)

int F(unsigned n)
{                                      // iterative, cheaper
  int fib1 = 1, fib2 = 1;
  for (int i = 3; i < n; i++)
  {
    int fib3 = fib1 + fib2;                      Iterative:
    fib1 = fib2;                                 O(_____)
    fib2 = fib3;
  }
  return fib2;
}

More complicated recursive functions are sometimes replaced by
iterative functions that use a stack to store the recursive calls. 10
                                                                   (See
Section 7.3)
             Recursive Examples
Example: (In C++ text. p.755: Problem 11)
This example explores the examination of a 2D structure (a grid).

In this simplistic representation, each element of a grid is blank or marked
by a special character. We want to search the grid to find the number of
"blobs" -- sets of contiguous asterisks ("*").




This classic example rests on the notion of using the recursive structure to
control searching in multiple directions. Linear evaluation is not sufficient
because most grid points have neighbors to the north, south, east and west.

Care must be taken here to control recursive invocation in order to prevent
infinite recursing. For example, one does not want to call one's south
neighbor and then be called by one's south neighbor, etc. Typically, one
alters the grid to indicate that a point has been visited.              11
                  Recursive Blobs
const int maxRow = 15;
const int maxCol = 15;
typedef char Grid[maxRow][maxCol];

void initGrid(Grid g, int & rows, int & cols);
int EatAllBlobs(Grid g, int rows, int cols);
void EatOneBlob(Grid g, int x, int y, int rows, int cols);

int main()
{
  Grid grid;
  int rows, cols;

    initGrid(grid, rows, cols);

    cout << "\nThere are " << EatAllBlobs(grid, rows, cols)
         << " blobs in there\n";

}
                                                              12
void initGrid(Grid g, int & rows, int & cols)
{
  cout << "# rows, # cols: ";
  cin >> rows >> cols;

    cout << "Enter grid of " << rows << " x " << cols
         << " grid of *'s and .'s:\n";
    for (int i = 0; i < rows; i++)
      for (int j = 0; j < cols; j++)
        cin >> (g[i][j]);
}
int EatAllBlobs(Grid g, int rows, int cols)
{
  int count = 0;

    for (int i = 0; i < rows; i++)
      for (int j = 0; j < cols; j++)
        if (g[i][j] == '*')
        {
          EatOneBlob(g, rows, cols, i, j);
          count++;
        }
    return count;                                       13
}
void EatOneBlob(Grid g, int rows, int cols, int x, int y)
{
  if (x < 0 || y < 0 || x >= rows || y >= cols)
    return;

    if (g[x][y] != '*')
      return;

    // else
    g[x][y] = '.';          // mark as visited

    EatOneBlob(g, rows, cols, x - 1, y);
    EatOneBlob(g, rows, cols, x + 1, y);
    EatOneBlob(g, rows, cols, x, y - 1);
    EatOneBlob(g, rows, cols, x, y + 1);
}

           # rows, # cols: 3 12
           Enter grid of 3 x 12 grid of *'s and .'s:
           ..***.***...
           ....*.*.*...
           **..***...**
                                                            14
           There are 3 blobs in there
        Recursive Permutations
Permutation generation is another classic example of the power of recursion
when used for backtracking.

Again, the recursive structure is used to complete path generation (in this
case permutations) from partial paths at all levels.


Here we permute a sequence of digits (characters could have just as easily
been used).

The basic idea is to fill an array with the digits and use the recursive
structure to systematically swap the digits to acquire all permutations.

Note the replacement of the digits following the recursive call.



                                                                           15
        Recursive Permutations
#include <iostream>
using namespace std;

const int maxValue = some_value;

void PrintPerm(int[] p)
{
   int index = 1;

    while (p[index] != 0)
    {
       cout << p[index];
       index = p[index]; // next number in permutation
    }

    cout << endl;
    return;
}

                                                         16
      Recursive Permutations
void Permute(int[] p, int k, int n)
{
   int index = 0;
   do
   {
       p[k] = p[index];
       p[index] = k;
       if (k == n)
          PrintPerm(p);
       else
          Permute(p, k+1, n);
       p[index] = p[k];    // swap back
       index = p[index];
   }
   while (p == 0);

    return;
}

                                          17
       Recursive Permutations
int main()
{
   int Perm[maxValue];
   int    number = 0;

    while (number <=0 || number > maxValue)
    {
        cout << "Enter number of elements to permute,
            less than " << maxValue-1 << endl;
        cin >> number;
    }

    Perm[0] = 0;
    Permute(Perm, 1, number);

    return 0;
}


                                                        18

								
To top