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

Laboratory Exercise on 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:

• InitializeStack
Sets topPosition to -1 to indicate an empty stack.
• Empty
Empty returns true or false, depending upon whether the stack contains any items or not.
• Full (optional)
Full returns true or false, depending upon whether the stack contains as much data as it can hold.
• Push
Push adds the specified item to the top of the stack.
• Pop
If the stack is not empty, Pop removes the top item from the stack, and this item is returned.
If the stack is empty, nothing is returned, and an error is reported.
• Top
If the stack is not empty, the top item is returned, but the contents of the stack are not changed.
If the stack is empty, nothing is returned, and an error is reported.

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. Consider the following stack functions:

• 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)

1. Why is stringStack * stack used as the parameter for initializeStack and pop, while the parameter for empty and top is stringStack (without the *)?

2. Complete the implementation of a stack of strings by implementing the these four stack operations.

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)

• void printFirstString (stringStack stack)
(scans all items on a stack and prints the one that comes first in alphabetical order)

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 struct node * stringStack;

struct node {
char str [MaxStack];
struct node * 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.

• 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.

Feedback Welcome

Development of laboratory exercises is an interative process. Prof. Walker welcomes your feedback! Feel free to talk to him during class or stop by his office.