Presentation is loading. Please wait.

Presentation is loading. Please wait.

Stacks & Recursion.

Similar presentations


Presentation on theme: "Stacks & Recursion."— Presentation transcript:

1 Stacks & Recursion

2 LIFO list - only top element is visible
Stack top push pop LIFO list - only top element is visible

3 Defining the ADT "Stack" Data: Basic Operations:
a linear collection of data items in which all operations occur at one end, called the top Basic Operations: construct a stack (usually starts empty) find out if stack is empty push: add an item on top of the stack accessing the topmost item Top: retrieve the top item of the stack Pop: remove the top item of the stack

4 Some Implementation choices
fixed-size array capacity (max # elements) decided at compile-time could be too small for expected amount of data could be too large, so space is wasted size (current # elements used) fast dynamic array capacity decided at run-time size may be less than or equal to the capacity uses pointers linked list size changes as needed during program execution

5 Implementation example
typedef Complx StackElement; const int CAPACITY = 8; int myTop; StackElement myStack[CAPACITY]; Complx X; push(&myStack,X); -1 myTop myArray 7 6 5 4 3 2 1 initially empty (myTop is negative)

6 Using the stack - 1 Model with an array
Let position 0 be top of stack Problem … consider pushing and popping Requires much shifting lab 1: build a stack, push, top - display (reverses input), pop Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson Education, Inc. All rights reserved

7 Using the stack - 2 A better approach is to let position 0 be the bottom of the stack Thus our design will include An array to hold the stack elements An integer to indicate the top of the stack Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson Education, Inc. All rights reserved

8 Addressing the problem
Too much or too little space Whatever size you pick, some day, there will be too much data In embedded systems, RAM is a premium Need a dynamic solution (later!) Size changes as needed No waste Slower when adding new elements

9 The "node" concept a "node" is one element of a stack
more than just the data index of next and/or previous node trivial for array implementations each node is a struct data may be an item INSIDE the node struct struct node {int next; Complx data;}; node myStackNode[CAPACITY];

10 An alternative to loops
Recursion An alternative to loops

11 What is recursion? a function calls itself a function calls its caller
direct recursion a function calls its caller indirect recursion f1 f f2

12 Recursion-1 Inefficient if duplicate values exist
Alternative to iteration (looping) often more "elegant" and concise than a loop sometimes very inefficient easier to program than loops Useful when a problem can be defined in terms of similar sub-problems eventually reach a "known" answer (base case) Inefficient if duplicate values exist

13 Head vs. Tail Recursion head recursion tail recursion
requires "deepest" call to complete before any values are known current stack state must be preserved tail recursion compiler can "collapse" the stack

14 Head vs. Tail recursion Note: base case is ALWAYS 1st
head(3) is: 2 3 tail(3) is: 3 2 1 void head(int n) { if(n == 1) return; else head(n-1); //  printf("head - n=%i\n",n);); } void tail(int n) { if(n == 0) return; else printf("tail - n=%i\n",n); tail(n-1); //  }

15 Caveats Static data is NOT on the "stack" Must have an "exit"
never gets re-allocated same values for EVERY call Must have an "exit" prevent an infinite loop

16 Outline of a Recursive Function
if (answer is known) provide the answer & exit else call same function with a smaller version of the same problem base case recursive case

17 Factorial (n) - looping
fact (int n) {if (n<0) exit(1); answer=1; for (i=1; i<=n; i++) answer=answer*i; // loop n times return (answer); } This is a simple problem

18 Factorial (n) – head recursive
definition: Factorial (n) = n * Factorial (n-1) int Fact (int n) {if (n<0) exit(1); if (n == 0 | n==1) return 1; return n * Fact (n-1); // stack must be saved // cannot do the *'s until last value is known }

19 Factorial "n" (tail recursive)
tail_fact (n, sofar) // init "sofar" same as "n" { if (n == 0 | n==1) return sofar; else // nothing to save on the stack // because it is in the 2nd parameter /* that is, the recursion may not HAVE to be done, if we have reached the base case */ return tail_fact (--n, sofar * n); } // here's how to run it printf ("5!=%i",tail_fact(5,5));

20 Keeping track compiler builds code to:
create a new stack pointer and stack space put local variables & parameters on stack each "return" returns control to caller's next instruction (the inst after the call) returned value, is in caller's stack space same as ANY function this is called "unwinding"

21 Recursive Call Tree int Fact (int n) { if (n == 0 | n==1) return 1;
24 6 2 int Fact (int n) { if (n == 0 | n==1) return 1; return n * Fact (n-1); }

22 Fibonacci Series Fibonacci sequence: 1, 1, 2, 3, 5, 8, 13, 21, ….
for n <= 2 fib(n) = fib(n-2) + fib(n-1) for n>2 for n=4: fib(2)+fib(3)  3

23 Tracing fib(6) 5 6 4 4 3 3 2 This is an animated slide!! 3 2 2 1 2 1 2 1 1 + 1 1

24 Ackermann's function A(0, n) = n + 1 A(m, 1) = A(m+1, 0)
A(m+1, n+1) = A(m, A(m+1, n)) This function build a VERY deep stack very quickly

25 What Does a Compiler Do? Lexical analysis Parsing Generate object code
divide a stream of characters into a stream of tokens total = cost * cost; if ( ( cond1 && ! cond2 ) ) Parsing do the tokens form a valid program, i.e. does it follow the syntax rules? Generate object code

26 BNF (Backus-Naur form) (also called Backus Normal Form)
a language used to define the syntax rules of a programming language consists of productions – rules for forming some construct of the language meta-symbols – symbols of BNF that are NOT part of the language being compiled terminals – appear as shown non-terminals – syntax defined by another production

27 BNF Syntax Rules for a simplified boolean expression
bexpr -> bterm || bexpr | bterm bterm -> bfactor && bterm | bfactor bfactor -> !bfactor | (bexpr) | true | false | ident ident -> alpha { alpha | digit|_} alpha -> a .. z | A .. Z digit -> meta-symbols are in red terminals are in blue non-terminals are in black special rules needed for "|" as part of a language

28 bexpr -> bterm || bterm | bterm
What sequence of tokens is a valid bexpr? if (there is a valid bterm) if (nextToken is ||) if (there is a valid bterm) return true else return false else return true else return false Note: tokenizer must watch for the "||" without stopping at the first "|"


Download ppt "Stacks & Recursion."

Similar presentations


Ads by Google