29
1 Stacks Chapter 4

1 Stacks Chapter 4. 2 Objectives You will be able to: Describe a stack as an ADT. Build a dynamic-array-based implementation of stacks. Build a linked-list

Embed Size (px)

Citation preview

1

Stacks

Chapter 4

2

Objectives

You will be able to: Describe a stack as an ADT. Build a dynamic-array-based implementation of

stacks. Build a linked-list implementation of stacks.

3

Stack

A stack is a last-in-first-out (LIFO) data structure.

Basic Operations:

Add an item Referred to as pushing it onto the stack

Remove an item Referred to as popping it from the stack

4

Stack as an ADT

Definition: An ordered collection of data items. Can be accessed only at one end, the top

Operations: Construct an empty stack Check if a stack is empty Push: Add an element to the top Pop: Remove the top element Top: Retrieve the top element

5

Example

Consider a program to convert decimal numbers to binary

Repeatedly Divide the decimal value by 2 Push the remainder onto a stack

Continue until quotient is 0

Pop values off the stack and output

6

A Simple Stack Template

Store stack elements in a dynamically allocated array.

Member variable identifies top of stack.

Throw an exception if client attempts to push an element when stack is full or pop an element when stack is empty.

7

Create Project

Create a new empty C++ Console Application Project Simple_Stack_Demo

Add stack.h Add stack_test.cpp Code is available at: http://www.cse.usf.edu/~turnerr/Data_Structures/Down

loads/2011_02_07_Stacks/

stack.h#pragma once

#include <iostream>

#include <cassert>

template <class T>

class Stack

{

public:

...

private:

T* data; // Dynamically allocated array

int size; // Number of elements

int top; // Index of element at top of stack

// -1 when stack is empty

};

stack.h#pragma once

#include <iostream>

#include <cassert>

template <class T>

class Stack

{

public:

Stack(int capacity = 1000);

~Stack();

bool IsEmpty() const {return top == -1;};

bool IsFull() const {return top == size-1;};

// Add a value to the top of the stack.

void Push(const T& value);

// Remove and return value at top of stack.

T Pop();

// Retrieve value at top of stack without removing it.

T Top() const;

// Display stack contents.

void Display(std::ostream& out) const;

10

Constructor and Destructor

template <class T>

Stack<T>::Stack(int capacity): top(-1), size(capacity)

{

data = new T[capacity];

assert (data != 0);

}

template <class T>

Stack<T>::~Stack()

{

delete[] data;

}

11

Push()

template <class T>

void Stack<T>::Push(const T& value)

{

if (this->IsFull())

{

throw "Stack overflow";

}

data[++top] = value;

}

12

Pop()

template <class T>

T Stack<T>::Pop()

{

if (this->IsEmpty())

{

throw "Pop called for empty stack";

}

return data[top--];

}

13

Top()

template <class T>

T Stack<T>::Top() const

{

if (this->IsEmpty())

{

throw "Top of empty stack requested";

}

return (data[top]);

}

14

stack_test.cpp

#include <iostream>

#include "Stack.h"

#include <assert.h>

using namespace std;

const int STACK_CAPACITY = 10;

int main()

{

Stack<int> s(STACK_CAPACITY);

assert (s.IsEmpty());

cout << "Newly created stack is empty\n";

printf ("Pushing 0 - %d \n", STACK_CAPACITY - 1);

for (int i = 0; i < STACK_CAPACITY; ++i)

{

s.Push(i);

}

cout << "Initial stack:\n";

s.Display(cout);

15

stack_test.cpp

assert(!s.IsEmpty());

cout << "Now the stack is not empty\n";

cout << "Adding one more element, which should cause overflow. " << endl;

try

{

s.Push(1);

cout << "ERROR\n"; // Should have thrown exception

}

catch (const char* msg)

{

cout << "Attempt to overfill stack threw exception as expected\n";

cout << "Message: " << msg << endl;

}

cout << "Stack should be unchanged\n" << endl;

s.Display(cout);

16

stack_test.cpp

cout << "Now poping elements off the stack\n";

while (!s.IsEmpty())

{

int top = s.Top();

cout << "Stack top: " << top << endl;

int next_item = s.Pop();

assert (next_item == top);

}

cout << "Stack is now empty\n";

cout << "Getting top of empty stack. This should fail\n";

try

{

int x = s.Top();

cout << "ERROR\n"; // Should have thrown exception

}

catch (const char* msg)

{

cout << "Attempt to get top of empty stack threw exception as expected\n";

cout << "Message: " << msg << endl;

}

17

stack_test.cpp

cout << "Doing one more pop. This should fail\n";

try

{

s.Pop();

cout << "ERROR\n"; // Should have thrown exception

cin.get();

}

catch (char* msg)

{

cout << "Attempt to pop empty stack threw exception as expected\n";

cout << "Message: " << msg << endl;

}

18

stack_test.cpp

cout << "Testing dynamic allocation\n";

Stack<int>* s2 = new Stack<int>(STACK_CAPACITY);

assert(s2 != 0);

cout << "Allocation was successful\n";

cout << "Testing delete\n";

delete(s2);

s2 = 0;

cout << "Delete was successful\n";

cout << "Test complete. Press Enter to exit." << endl;

cin.get(); // Hold window open

return 0;

}

19

Program Running

20

Program Running

21

An Application: Decimal to Binary Conversion

stack_demo.cpp

/*--------------------------------------------------------------

This program uses a stack to convert the base-ten representation

of a positive integer entered as input to base two, which is

then output.

---------------------------------------------------------------------*/

#include <iostream>

#include "Stack.h"

using namespace std;

int main()

{

int number; // the number to be converted

int remainder; // remainder when number is divided by 2

Stack<int> remainders; // stack of remainders

cout << "This program displays the binary representation of integers\n";

cout << "that you specify. Enter 0 to end program\n\n";

22

stack_demo.cpp

while (true)

{

cout << "Enter positive integer to convert: ";

cin >> number;

if (number <= 0)

{

break;

}

while (number != 0)

{

remainder = number % 2;

remainders.Push(remainder);

number /= 2;

}

cout << "Base-two representation: ";

while (!remainders.IsEmpty() )

{

remainder = remainders.Pop();

cout << remainder;

}

cout << endl << endl;

}

23

stack_demo.cpp

cin.get(); // Hold window open

cin.get();

return 0;

}

24

Program in Action

25

Allocation Failure

Let’s see if we can force an allocation failure and see what happens.

Stack<int> remainders(INT_MAX); // stack of remainders

26

stack_test.cpp

#include <iostream>

#include "Stack.h"

#include <cassert>

using namespace std;

int main()

{

try

{

Stack* s = new Stack<int>(INT_MAX);

assert(s != 0);

cout << "Allocation was successful\n";

}

catch (bad_alloc& ba)

{

cout << "Caught Bad Allocation exception\n";

cout << ba.what() << endl;

}

cout << "Test complete. Press enter to exit.\n";

cin.get(); // Hold window open

return 0;

}

27

Running on Windows

Click here

28

Running on Windows

29

Running on Linux