You are on page 1of 9

UNIT 2: FURTHER TOPICS IN COMPUTER SCIENCE

MODULE 1: Data Structures

What is a data structure?


A data structure is a specific way of organizing, processing,
retrieving and storing data. A data structure provides a defined
way of representing entities and their operations in the real
world in a way that allows manipulation by the processor.

Abstract Data Types (ADTs)


An ADT is a type or class for objects whose behavior is defined
by a set value and a set of operations. However, while an ADT
mentions the operations, the actual implementation and
organization of data is not visible to the user. The abstraction
comes the implementation-independent view.

Source: https://geeksforgeeks.org/

The ADTs covered in this course are:


1. Stacks (implementation using arrays and linked lists)
2. Queue (implementation using arrays and linked lists)
3. Linked Lists

© Rafena Mustapha 1
STACKS: Array Implementation

A stack contains elements of the same type arranged in


sequential order. This ADT follows the principle of LIFO (Last
In First Out). Imagine a stack of books. New books are added to
the top of the stack and removed from the top as well.

All operations take place at a single end that is the top of the
stack and following operations can be performed:
1. push() – Insert an element at one end of the stack called top.
2. pop() – Remove and return the element at the top of the stack,
if it is not empty.
3. peek() – Return the element at the top of the stack without
removing it, if the stack is not empty.
4. isEmpty() – Return true if the stack is empty, otherwise
return false.
5. isFull() – Return true if the stack is full, otherwise return
false.

We use the following code in C to implement a stack using


arrays:

#include <stdio.h>

int MAXSIZE = 8; //the total number of elements the stack can hold
int stack[8]; //an array of integers called “stack” that can store 8 elements
int top = -1; //variable to keep track of the array index that contains the
//element at the TOP of the stack

/*This function checks if the stack is empty. Array indices start from 0. Our array of 8
elements will be indexed from 0 to 7. Hence, at -1 no array exists so we use this to
represent an empty stack. If we had set top=0, then stack[0] exists – this is the FIRST
element of the stack. TOP points to the element at the top of the stack. We cannot point to
index 0 if nothing is there. We point to index 0 if the stack has 1 element which is the
top of the stack.*/

int isEmpty() { // the function returns an integer

if(top == -1) //if the stack is empty (since top=-1)


return 1; // we return 1 – think of this as “true – yes, the stack is empty
else
return 0; //false or no, the stack is not empty
}

/*This function checks if the stack if full. The size of an array must be defined when it
is declared. The size of the array is the maximum number of elements it can accommodate. In
this case, 8 */
int isFull() { //function returns an integer

© Rafena Mustapha 2
if(top == MAXSIZE) //we check that the top element is not the maximum capacity
//of the stack
return 1; // return 1 or “true” if the stack is full
else
return 0; //return 0 or “false” if it is not full
}

/* This function returns the element at the very top of the stack. hence “peek” */
int peek() { //functions returns an integer
return stack[top]; //return the element at the top of the stack
}

/*This function removes an element from the stack. Recall that removal happens on the top
element, as you would remove a book from the top of a stack. We say that we “pop an element
from the stack.” This function returns an integer because we do not want to blindly remove
elements from our stack. We want to know what we have removed, so this value is sent back
to the processor when pop() is called. */
int pop() {
int data; //this variable will store the element that is being removed.
//NOTE: it will store the value itself being removed, NOT the index where the value was
//stored.

if(!isEmpty()) { //we check that our stack is not empty. This caters to the
//problem of stack underflow (explained later)
data = stack[top]; //collects the value being removed into the data variable
top = top - 1; //move the top index DOWN
return data; //return the value that was removed to the processor
} else {
printf("Could not retrieve data, Stack is empty.\n");
} //prints error message if there is stack underflow
}

/*This function adds an element to the stack. Recall that an element has to be added to the
TOP of the stack. We say that we “push an element onto the stack.” NOTE: The return value
of the function has been changed to “void” because this is the way CAPE designs the
algorithm. It is okay to return int where the return value will be whatever value we have
added to the stack. */
void push(int data) { //This function takes an integer argument. How do we know
//what to add to the top of the stack? The user must input this value.

if(!isFull()) { //check that our stack is not already full before adding
//a new element. This caters to the problem of stack overflow (explained later)
top = top + 1; //update the top index first so that we do not overwrite
//the current value at the top
stack[top] = data; //set the value of the top index equal to the value the
//user inputs
} else {
printf("Could not insert data, Stack is full.\n");
} //prints error message if there is stack overflow
}

© Rafena Mustapha 3
Removing an item from a stack – pop()

Index Data
7
6
5
TOP à 4 50 ß stack[top]
3 40
2 30
1 20
0 10
stack

data = stack[top];
Index Data
7
6
5
TOP à 4 50 ß stack[top]
3 40
2 30 put this value into data
1 20
0 10
stack

top = top – 1;
Index Data Index Data
7 7
6 6
5 5
4 50 4
TOP à 3 40 ß stack[top] TOP à 3 40 ß stack[top]
2 30 2 30
1 20 1 20
0 10 0 10
stack stack

© Rafena Mustapha 4
STACK UNDERFLOW

Stack underflow occurs if you try remove an item from empty


stack. We must avoid this situation because in the array
implementation, it will result in an array out of bounds
exception. An array out of bounds exception occurs when there is
an attempt to access an array location that does not exist in
memory. We must check that a stack is not empty before
attempting to pop an item to prevent his problem.

This is done using a simple conditional statement that uses the


prior written isEmpty() function:
if(!isEmpty()) {
data = stack[top];
top = top - 1;
return data;
} else {
printf("Could not retrieve data, Stack is empty.\n");
}
}

Why does this occur?


We set top equal to -1 to represent an empty stack. An array
never has an index equal to -1 because arrays are indexed from 0
to 1 minus the maximum size of the array.

We cannot set top equal to 0 because when we create the stack in


the beginning, index 0 is already set in memory. This is why we
set the top equal to an index that does not exist.

© Rafena Mustapha 5
Adding an item to a stack – push()

Index Data
7
6
5
TOP à 4 50 ß stack[top]
3 40
2 30
1 20
0 10
stack

top = top + 1;
Index Data
7
6
TOP à 5 ß stack[top]
4 50
3 40
2 30
1 20
0 10
stack

stack[top] = data;
Index Data
7
If we call the function with
6 push(60), 60 is pushed onto
TOP à 5 60 ß stack[top] the stack
4 50
3 40
2 30
1 20 Index Data
0 10 7
stack 6
TOP à 5 60 ß stack[top]
4 50
3 40
2 30
1 20
0 10
stack

© Rafena Mustapha 6
STACK OVERFLOW

Stack overflow occurs if you try to add a new item to an already


full stack. This will again result in an array out of bounds
exception in the array implementation of a stack.

For example, in our code the maximum number of elements the


array can hold is 8. Upon creation of our stack in the line int
stack[8]; eight units of memory are allocated to the array. If we
try to add a 9th element, the processor attempts to access the
index 8 of the array, or the value stored in stack[8]. NO SUCH
location exists because our 8-sized array is only indexed up to
7 (indexing starts at 0).

We, therefore, check that the stack is not full before adding a
new item. This is done by using the existing isFull() function:

if(!isFull()) {
top = top + 1;
stack[top] = data;
} else {
printf("Could not insert data, Stack is full.\n");
}
}

© Rafena Mustapha 7
APPLICATION OF STACKS

Some major applications of stacks are:


Memory management and program execution: Any modern computer
environment uses a stack as the primary memory management model
for a running program.

Each program that is running in a computer system has its own


memory allocation containing the typical layout as shown below.

Source:
http://jcsites.juniata.edu/faculty/kruse/cs240/stackapps.htm

Backtracking

Backtracking is used in algorithms in which there are steps


along some path (state) from some starting point to some goal.

• Find your way through a maze.


• Find a path from one point in a graph (roadmap) to another
point.
• Play a game in which there are moves to be made (checkers,
chess).

In all of these cases, there are choices to be made among a


number of options. We need some way to remember these decision
points in case we want/need to come back and try the alternative

© Rafena Mustapha 8
Consider the maze. At a point where a choice is made, we may
discover that the choice leads to a dead-end. We want to
retrace back to that decision point and then try the other
(next) alternative.

Again, stacks can be used as part of the solution. Recursion is


another, typically more favored, solution, which is actually
implemented by a stack.

Expression Evaluation

Stack data structure is used for evaluating the given


expression. For example, consider the following expression
5 * ( 6 + 2 ) - 12 / 4

Since parenthesis has the highest precedence among the


arithmetic operators, ( 6 +2 ) = 8 will be evaluated first. Now,
the expression becomes
5 * 8 - 12 / 4

* and / have equal precedence and their associativity is from


left-to-right. So, start evaluating the expression from left-to-
right.
5 * 8 = 40 and 12 / 4 = 3

Now, the expression becomes


40 - 3

And the value returned after the subtraction operation is 37.

© Rafena Mustapha 9

You might also like