CSC 161 Grinnell College Fall, 2011
 
Imperative Problem Solving and Data Structures
 
 

Stacks

Goals

The main goal of this lab is to gain facility with two common methods of implementing the data organization type called stacks.

Lab Exercises

Create a directory for this lab in your directory for this class, and move to the lab directory.

Part A: Stacks with Arrays

The reading describes a stack as an object that can store data and that has the following operations:

Within C, there is no way to combine underlying data structures (e.g., arrays) and operations within a single structure. (Such a combined ADT can be done in C++ or Java, but we leave those languages for other courses!) Instead, we will define variables for each stack needed. For each operation, we will pass the relevant variables as parameters, so we can use the same functions for multiple stacks. This approach requires that the data items for the stack have the same type (e.g., a stack of doubles or a stack of strings).

For this section of the lab, we will focus on arrays of strings, and this leads to the following declarations for stacks of fruits, vegetables, and pastries:

    #define MaxStack  50  /* MaxStack stands for the size of all stack arrays */

    typedef struct {
    int topPosition;
    char * stackArray [MaxStack];
    } stringStack;      /* type for a stack of strings */
  

With this framework, the full and push operations might be defined as follows:

    int full (stringStack stack) {
    /* determine if there are more positions in a stackArray */
    return (stack.topPosition == (MaxStack-1));
    }

    int push (stringStack *stack, char * item) {
    /* return -1 if stack full */
    if (full (*stack)) {
    printf ("attempt to push item onto an already full stack\n");
    return -1;
    }

    /* add item to stack */
    (stack->topPosition) ++;
    stack->stackArray[stack->topPosition] = item;
    }
  1. Complete the implementation of a stack of strings by implementing the remaining operations:

    • void initializeStack (stringStack * stack) (sets topPosition of stack to -1)
    • int empty (stringStack stack)
    • char * pop (stringStack *stack) (returns 0 if stack is empty, otherwise removes the top string from the stack and returns it)
    • char * top (stringStack stack) (returns 0 if stack is empty, otherwise returns the top string on the stack)
  2. After writing functions, it is important to test your code to ensure that it works as you expected and accounts for unusual cases. Declare and initialize three stacks within your main program for fruit, vegetables, and pastry. Test your code by executing the following instructions:

    • Push "apple" and "orange" onto the fruit stack.
    • Push "doughnut" onto the pastry stack.
    • Check if the three stacks are empty.
    • Push "corn", "beans", "squash", and "broccoli" onto the vegetable stack.
    • Print the top of each stack.
    • Pop one item off the pastry stack and print it.
    • Print the top of each stack.

      Hint: the pastry stack is empty. Be careful!

    • Pop three items off the vegetable stack and print.
    • Pop three items off the fruit stack and print.

      Hint: how many items are on the fruit stack initially?

    • Push "cake" onto the pastry stack.
    • Check if any of the three stacks is empty.
  3. Add the following procedures to the code:

    • int size (stringStack stack)
      (returns the number of items currently on the stack)
    • void print (stringStack stack)
      (prints all of the current elements on the stack)
    • char * get_nth (stringStack stack, int nth)
      (returns the string at the nth position from the top of the stack)

Part B: Stacks with Linked Lists

The earlier section on stacks described the following function prototypes:

  int empty (stringStack stack)
  int full (stringStack stack)      
  void initializeStack (stringStack * stack) 
  char * pop (stringStack *stack) 
  int push (stringStack *stack, char * item) 
  char * top (stringStack stack)

The section of the reading regarding linked lists discusses these functions in the context of linked lists with these declarations:

   typedef stackNode * stringStack;

   struct node {
      char str [MaxStack];
      struct stackNode * next;
   } stackNode;     

   stringStack stack;
  1. Copy the program you wrote for the earlier section on stacks with arrays and modify it, so that the stacks are implemented by linked lists. In this, you will need to change the bodies of the prototype functions, and you will need to change the declaration of the stack variables for the three stacks (fruits, vegetables, and pastries) used in testing. However, you should not have to change any of the code used for testing, and the output of this new program should be identical in all respects to the output of the program from the previous section.

  2. As with the previous lab on stacks with arrays, expand the code for the stack ADT implementation to include these functions:

    • a size function which will return the number of items currently on the stack,

    • a print function which will print all of the current elements on the stack, and

    • an nth function which takes one parameter (an index) and returns the item at that position from the top in the current stack.

  3. Write a printReverse function that prints all items on a stack, from the bottom of the stack to the top. (Thus, the top item will be printed last.)

    Hint: Consider printReverse as a husk procedure that calls a recursive kernel procedure to move along the stack's list and do the printing.

  4. Write a printFirstString function that scans all items on a stack and prints the one that comes first in alphabetical order.

Reminder: Complete Evaluation Form

When you have finished this lab, be sure to fill out its evaluation form in the "Lab Evaluation" section for CSC 161 on Pioneer Web.