Professional Documents
Culture Documents
Unit number and title Unit 19: Data Structures and Algorithms
Student declaration
I certify that the assignment submission is entirely my own work and I fully understand the consequences of plagiarism. I understand that
making a false declaration is a form of malpractice.
Student’s signature
Grading grid
P1 P2 P3 M1 M2 M3 D1 D2
Summative Feedback: Resubmission Feedback:
Academic Year
Unit Tutor
Submission Format:
Format: The submission is in the form of an individual written report and a presentation. This should
be written in a concise, formal business style using single spacing and font size 12. You are
required to make use of headings, paragraphs and subsections as appropriate, and all work
must be supported with research and referenced using the Harvard referencing system.
Please also provide a bibliography using the Harvard referencing system.
Submission Students are compulsory to submit the assignment in due date and in a way requested by
the Tutors. The form of submission will be a soft copy in PDF posted on corresponding
course of http://cms.greenwich.edu.vn/
Note: The Assignment must be your own work, and not copied by or from another student or from
books etc. If you use ideas, quotes or data (such as diagrams) from books, journals or other sources, you
must reference your sources, using the Harvard style. Make sure that you know how to reference
properly, and that understand the guidelines on plagiarism. If you do not, you definitely get fail
Scenario: You work as in-house software developer for Softnet Development Ltd, a software body-shop providing
network provisioning solutions. Your company is part of a collaborative service provisioning development project
and your company has won the contract to design and develop a middleware solution that will interface at the
front-end to multiple computer provisioning interfaces including SOAP, HTTP, JML and CLI, and the back-end
telecom provisioning network via CLI .
Your account manager has assigned you a special role that is to inform your team about designing and
implementing abstract data types. You have been asked to create a presentation for all collaborating partners on
how ADTs can be utilised to improve software design, development and testing. Further, you have been asked to
write an introductory report for distribution to all partners on how to specify abstract data types and algorithms in
a formal notation.
Tasks
Part 1
You will need to prepare a presentation on how to create a design specification for data structures, explaining the
valid operations that can be carried out on the structures using the example of:
1. A stack ADT, a concrete data structure for a First In First out (FIFO) queue.
2. Two sorting algorithms.
3. Two network shortest path algorithms.
Part 2
You will need to provide a formal written report that includes the following:
1. Explanation on how to specify an abstract data type using the example of software stack.
2. Explanation of the advantages of encapsulation and information hiding when using an ADT.
3. Discussion of imperative ADTs with regard to object orientation.
Contents
LO1 Examine abstract data types, concrete data structures and algorithms ............................................... 1
P1 Create a design specification for data structures explaining the valid operations that can be
carried out on the structures........................................................................................................................... 19
A. Linked list ........................................................................................................................................................ 20
B. Selection sort .................................................................................................................................................. 20
C.Selection sort ............................................................................................................................................... 20
D.Bubble sort .................................................................................................................................................. 20
E.Linear search .................................................................................................................................................... 20
F. Binary search ................................................................................................................................................... 23
G Dijkstra algorithm ................................................................................................................................................ 24
H.Bellman-Ford algorithm ...................................................................................................................................... 28
P2 Determine the operations of a memory stack and how it is used to implement function calls in a
computer................................................................................................................................................................ 34
P3 Using an imperative definition, specify the abstract data type for a software stack. ....................... 34
Reference ................................................................................................................................................................ 34
ASSIGNMENT 1 ANSWERS
LO1 Examine abstract data types, concrete data structures and
algorithms
P1 Create a design specification for data structures explaining the
valid operations that can be carried out on the structures.
A. Linked list
A linked list is a way to store a collection of elements. Like an array these can be character or integers. Each
element in a linked list is stored in the form of a node.
Node:
A node is a collection of two sub-elements or parts. A data part that stores the element and a next part that
stores the link to the next node.
Linked List:
A linked list is formed when many such nodes are linked together to form a chain. Each node points to the next
node present in the order. The first node is always used as a reference to traverse the list and is called HEAD.
The last node points to NULL.
Page |1
Declaring a Linked list :
struct LinkedList{
int data;
struct LinkedList *next;
};
The above definition is used to create every node in the list. The data field stores the element and the next is a
pointer to store the address of the next node.
In place of a data type, struct LinkedList is written before next. That's because its a self-referencing pointer. It
means a pointer that points to whatever it is a part of. Here next is a part of a node and it will point to the next
node.
Creating a Node:
typedef struct LinkedList *node; //Define node as pointer of data type struct LinkedList
node createNode(){
node temp; // declare a node
temp = (node)malloc(sizeof(struct LinkedList)); // allocate memory using malloc()
temp->next = NULL;// make next point to NULL
return temp;//return the new node
}
malloc() is used to dynamically allocate a single block of memory in C, it is available in the header file stdlib.h.
sizeof() is used to determine size in bytes of an element in C. Here it is used to determine size of each node and
sent as a parameter to malloc.
The above code will create a node with data as value and next pointing to NULL.
Here the new node will always be added after the last node. This is known as inserting a node at the rear end.
This type of linked list is known as simple or singly linked list. A simple linked list can be traversed in only one
direction from head to the last node.
p->next = NULL;
Here -> is used to access next sub element of node p. NULL denotes no node exists after the current node , i.e.
its the end of the list.
The linked list can be traversed in a while loop by using the head node as a starting reference:
node p;
p = head;
while(p != NULL){
p = p->next;
}
B. Selection sort
The Selection sort algorithm is based on the idea of finding the minimum or maximum element in an unsorted
array and then putting it in its correct position in a sorted array.
int minimum;
// reduces the effective size of the array by one in each iteration.
Page |4
Time Complexity:
To find the minimum element from the array of $$N$$ elements, $$N-1$$ comparisons are required. After
putting the minimum element in its proper position, the size of an unsorted array reduces to $$N-1$$ and then
$$N-2$$ comparisons are required to find the minimum in the unsorted array.
Therefore $$(N-1)$$ + $$(N-2 )$$ + $$.......$$ + $$1$$ = $$( N \cdot (N-1) ) / 2$$ comparisons and $$N$$ swaps
result in the overall complexity of $$O( N^2 )$$.
C. Bubble sort
Sorting Algorithms are concepts that every competitive programmer must know. Sorting algorithms can be
used for collections of numbers, strings, characters, or a structure of any of these types.
Bubble sort is based on the idea of repeatedly comparing pairs of adjacent elements and then swapping their
positions if they exist in the wrong order.
Assume that $$A [ ]$$ is an unsorted array of $$n$$ elements. This array needs to be sorted in ascending order.
The pseudo code is as follows:
In step 1, $$7$$ is compared with $$4$$. Since $$7 \gt 4$$, $$7$$ is moved ahead of $$4$$. Since all the other
elements are of a lesser value than $$7$$, $$7$$ is moved to the end of the array.
In step 2, $$4$$ is compared with $$5$$. Since $$5 \gt 4$$ and both $$4$$ and $$5$$ are in ascending order,
these elements are not swapped. However, when $$5$$ is compared with $$2$$, $$5 \gt 2$$ and these
elements are in descending order. Therefore, $$5$$ and $$2$$ are swapped.
In step 3, the element $$4$$ is compared with $$2$$. Since $$4 \gt 2$$ and the elements are in descending
order, $$4$$ and $$2$$ are swapped.
Page |6
The sorted array is $$A[]=\{2, 4, 5, 7\}$$.
Complexity:
The complexity of bubble sort is $$O(n^2)$$ in both worst and average cases, because the entire array needs to
be iterated for every element.
D. Linear Search
Linear search is used on a collections of items. It relies on the technique of traversing a list from start to end by
exploring properties of all the elements that are found on the way.
For example, consider an array of integers of size $$N$$. You should find and print the position of all the
elements with value $$x$$. Here, the linear search is based on the idea of matching each element from the
beginning of the list to the end of the list with the integer $$x$$, and then printing the position of the element
if the condition is `True'.
Implementation:
If you want to determine the positions of the occurrence of the number $$7$$ in this array. To determine the
positions, every element in the array from start to end, i.e., from index $$1$$ to index $$10$$ will be compared
with number $$7$$, to check which element matches the number $$7$$.
Time Complexity:
Page |7
The time complexity of the linear search is $$O(N)$$ because each element in an array is compared only once.
E.Binary Search
Binary search is the most popular Search algorithm.It is efficient and also one of the most commonly used
techniques that is used to solve problems.
If all the names in the world are written down together in order and you want to search for the position of a
specific name, binary search will accomplish this in a maximum of $$35$$ iterations.
Binary search works only on a sorted set of elements. To use binary search on a collection, the collection must
first be sorted.
When binary search is used to perform operations on a sorted set, the number of iterations can always be
reduced on the basis of the value that is being searched.
By using linear search, the position of element 8 will be determined in the $$9^{th}$$ iteration.
Let's see how the number of iterations can be reduced by using binary search. Before we start the search, we
need to know the start and end of the range. Lets call them Low and High.
Low = 0
High = n-1
Now, compare the search value $$K$$ with the element located at the median of the lower and upper bounds.
If the value $$K$$ is greater, increase the lower bound, else decrease the upper bound.
Page |8
Referring to the image above, the lower bound is $$0$$ and the upper bound is $$9$$. The median of the
lower and upper bounds is (lower_bound + upper_bound) / 2 = 4. Here a[4] = 4. The value 4>2, which is the
value that you are searching for. Therefore, we do not need to conduct a search on any element beyond 4 as
the elements beyond it will obviously be greater than 2.
Therefore, we can always drop the upper bound of the array to the position of element 4. Now, we follow the
same procedure on the same array with the following values:
Low: 0
High: 3
Repeat this procedure recursively until Low > High. If at any iteration, we get $$a[mid]= key$$, we return value
of $$mid$$. This is the position of $$key$$ in the array. If $$key$$ is not present in the array, we return $$-1$$.
Implementation:
Time complexity
As we dispose off one part of the search case during every step of binary search, and perform the search
operation on the other half, this results in a worst case time complexity of $$O(log _{2} N) $$.
F.Dijkstra algorithm
Dijkstra's algorithm (or Dijkstra's Shortest Path First algorithm, SPF algorithm)[1] is an algorithm for finding
the shortest paths between nodes in a graph, which may represent, for example, road networks. It was
conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later.[2][3][4]
The algorithm exists in many variants. Dijkstra's original algorithm found the shortest path between two given
nodes,[4] but a more common variant fixes a single node as the "source" node and finds shortest paths from the
source to all other nodes in the graph, producing a shortest-path tree.
For a given source node in the graph, the algorithm finds the shortest path between that node and every
other.[5]:196–206 It can also be used for finding the shortest paths from a single node to a single destination node
by stopping the algorithm once the shortest path to the destination node has been determined. For example, if
the nodes of the graph represent cities and edge path costs represent driving distances between pairs of cities
connected by a direct road (for simplicity, ignore red lights, stop signs, toll roads and other obstructions),
Dijkstra's algorithm can be used to find the shortest route between one city and all other cities. A widely used
application of shortest path algorithm is network routing protocols, most notably IS-IS (Intermediate System to
Intermediate System) and Open Shortest Path First (OSPF). It is also employed as a subroutine in other
algorithms such as Johnson's.
The Dijkstra algorithm uses labels that are positive integers or real numbers, which are totally ordered. It can be
generalized to use any labels that are partially ordered, provided the subsequent labels (a subsequent label is
produced when traversing an edge) are monotonically non-decreasing. This generalization is called the generic
Dijkstra shortest-path algorithm.[6]
Dijkstra's algorithm uses a data structure for storing and querying partial solutions sorted by distance from the
start. The original algorithm uses a min-priority queue and runs in time (where is the number of
nodes). The idea of this algorithm is also given in Leyzorek et al. 1957. Fredman & Tarjan 1984 propose using
a Fibonacci heap min-priority queue to optimize the running time complexity to (where is the
number of edges). This is asymptotically the fastest known single-source shortest-path algorithm for
arbitrary directed graphs with unbounded non-negative weights. However, specialized cases (such as
bounded/integer weights, directed acyclic graphs etc.) can indeed be improved further as detailed
in Specialized variants.
In some fields, artificial intelligence in particular, Dijkstra's algorithm or a variant of it is known as uniform cost
search and formulated as an instance of the more general idea of best-first search.[7]
P a g e | 10
Let the node at which we are starting be called the initial node. Let the distance of node Y be the distance from
the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them
step by step.
1. Mark all nodes unvisited. Create a set of all the unvisited nodes called the unvisited set.
2. Assign to every node a tentative distance value: set it to zero for our initial node and to infinity for all
other nodes. Set the initial node as current.[13]
3. For the current node, consider all of its unvisited neighbours and calculate their tentative distances
through the current node. Compare the newly calculated tentative distance to the current assigned
value and assign the smaller one. For example, if the current node A is marked with a distance of 6, and
the edge connecting it with a neighbour B has length 2, then the distance to B through A will be 6 + 2 =
8. If B was previously marked with a distance greater than 8 then change it to 8. Otherwise, the current
value will be kept.
4. When we are done considering all of the unvisited neighbours of the current node, mark the current
node as visited and remove it from the unvisited set. A visited node will never be checked again.
5. If the destination node has been marked visited (when planning a route between two specific nodes) or
if the smallest tentative distance among the nodes in the unvisited set is infinity (when planning a
complete traversal; occurs when there is no connection between the initial node and remaining
unvisited nodes), then stop. The algorithm has finished.
6. Otherwise, select the unvisited node that is marked with the smallest tentative distance, set it as the
new "current node", and go back to step 3.
When planning a route, it is actually not necessary to wait until the destination node is "visited" as above: the
algorithm can stop once the destination node has the smallest tentative distance among all "unvisited" nodes
(and thus could be selected as the next "current").
G.Bellman-Ford algorithm
The Bellman–Ford algorithm is an algorithm that computes shortest paths from a single source vertex to all of
the other vertices in a weighted digraph.[1] It is slower than Dijkstra's algorithm for the same problem, but more
versatile, as it is capable of handling graphs in which some of the edge weights are negative numbers. The
algorithm was first proposed by Alfonso Shimbel (1955), but is instead named after Richard Bellman and Lester
Ford Jr., who published it in 1958 and 1956, respectively.[2] Edward F. Moore also published the same algorithm
in 1957, and for this reason it is also sometimes called the Bellman–Ford–Moore algorithm.[1]
Negative edge weights are found in various applications of graphs, hence the usefulness of this algorithm.[3] If a
graph contains a "negative cycle" (i.e. a cycle whose edges sum to a negative value) that is reachable from the
source, then there is no cheapest path: any path that has a point on the negative cycle can be made cheaper by
one more walk around the negative cycle. In such a case, the Bellman–Ford algorithm can detect and report the
negative cycle.[1][4]
Like Dijkstra's algorithm, Bellman–Ford proceeds by relaxation, in which approximations to the correct distance
are replaced by better ones until they eventually reach the solution. In both algorithms, the approximate
distance to each vertex is always an overestimate of the true distance, and is replaced by the minimum of its
old value and the length of a newly found path.
P a g e | 11
::distance[],predecessor[]
distance[source] := 0 // The distance from the source to itself is, of course, zero
Stacks are dynamic data structures that follow the Last In First Out (LIFO) principle. The last item to be inserted
into a stack is the first one to be deleted from it.
For example, you have a stack of trays on a table. The tray at the top of the stack is the first item to be moved if
you require a tray from that stack.
Stacks have restrictions on the insertion and deletion of elements. Elements can be inserted or deleted only
from one end of the stack i.e. from the $$top$$. The element at the top is called the $$top$$ element. The
operations of inserting and deleting elements are called $$push()$$ and $$pop()$$ respectively.
When the top element of a stack is deleted, if the stack remains non-empty, then the element just below the
previous top element becomes the new top element of the stack.
P a g e | 12
For example, in the stack of trays, if you take the tray on the top and do not replace it, then the second tray
automatically becomes the top element (tray) of that stack.
Features of stacks
Operations
P a g e | 13
pop( ): Removes an element from the top of a stack
if( isEmpty ( ) )
{
cout << “Stack is empty. Underflow condition! ” << endl ;
}
else
{
top = top - 1 ; //Decrementing top’s position will detach last element from stack
}
}
int topElement ( )
{
return stack[ top ];
}
bool isEmpty ( )
{
if ( top == -1 ) //Stack is empty
return true ;
else
return false;
}
int size ( )
{
return top + 1;
}
Implementation
#include <iostream>
using namespace std;
P a g e | 14
int top = -1; //Globally defining the value of top as the stack is empty
if( isEmpty ( ) )
{
cout << "Stack is empty. Underflow condition! " << endl ;
}
else
{
top = top - 1 ; //Decrementing top’s position will detach last element from stack
}
}
int size ( )
{
return top + 1;
}
int topElement (int stack[])
{
return stack[ top ];
}
//Let's implement these functions on the stack given above
int main( )
{
int stack[ 3 ];
// pushing element 5 in the stack .
push(stack , 5 , 3 ) ;
P a g e | 15
cout << "Current size of stack is " << size ( ) << endl ;
push(stack , 10 , 3);
push (stack , 24 , 3) ;
cout << "Current size of stack is " << size( ) << endl ;
//As the stack is full, further pushing will show an overflow condition.
push(stack , 12 , 3) ;
//As the stack is empty , further popping will show an underflow condition.
pop ( );
Output
Refer to the following image for more information about the operations performed in the code.
P a g e | 16
P a g e | 17
Application
You have a bracket sequence made up of opening '(' and closing ')' parentheses. You must check if this bracket
sequence is balanced.
A bracket sequence is considered balanced if for every prefix of the sequence, the number of opening brackets
is greater than or equal to the number of closing brackets, and the total number of opening brackets is equal to
the number of closing brackets.
You can maintain a stack where you store a parenthesis. Whenever, you come across an opening parenthesis,
$$push$$ it in the stack. However, whenever you come across a closing parenthesis, $$pop$$ a parenthesis
from the stack.
#include <iostream>
using namespace std;
int top;
void check (char str[ ], int n, char stack [ ])
{
for(int i = 0 ; i < n ; i++ )
{
if (str [ i ] == ‘(’)
{
top = top + 1;
stack[ top ] = ‘ ( ’;
}
if(str[ i ] == ‘)’ )
{
if(top == -1 )
{
top = top -1 ;
break ;
}
else
{
top = top -1 ;
}
}
}
if(top == -1)
cout << “String is balanced!” << endl;
else
cout << “String is unbalanced!” << endl ;
}
P a g e | 18
int main ( )
{
//balanced parenthesis string.
char str[ ] = { ‘(‘ , ‘a’ , ‘+’, ‘ ( ’, ‘b ’ , ‘-’ , ‘ c’ ,‘)’ , ‘ ) ’} ;
// unbalanced string .
char str1 [ ] = { ‘(’ , ‘(’ , ‘a’ , ‘ + ’ , ‘ b’ , ‘)’ } ;
char stack [ 15 ] ;
top = -1;
check (str , 9 , stack ); //Passing balanced string
top = -1 ;
check(str1 , 5 , stack) ; //Passing unbalanced string
return 0;
Output
String is balanced!
String is unbalanced!
B.Memory stack
The Stack
What is the stack? It's a special region of your computer's memory that stores temporary variables created by
each function (including the main() function). The stack is a "LIFO" (last in, first out) data structure, that is
managed and optimized by the CPU quite closely. Every time a function declares a new variable, it is "pushed"
onto the stack. Then every time a function exits, all of the variables pushed onto the stack by that function, are
freed (that is to say, they are deleted). Once a stack variable is freed, that region of memory becomes available
for other stack variables.
The advantage of using the stack to store variables, is that memory is managed for you. You don't have to
allocate memory by hand, or free it once you don't need it any more. What's more, because the CPU organizes
stack memory so efficiently, reading from and writing to stack variables is very fast.
A key to understanding the stack is the notion that when a function exits, all of its variables are popped off of
the stack (and hence lost forever). Thus stack variables are local in nature. This is related to a concept we saw
earlier known as variable scope, or local vs global variables. A common bug in C programming is attempting to
access a variable that was created on the stack inside some function, from a place in your program outside of
that function (i.e. after that function has exited).
Another feature of the stack to keep in mind, is that there is a limit (varies with OS) on the size of variables that
can be stored on the stack. This is not the case for variables allocated on the heap.
P a g e | 19
• the stack grows and shrinks as functions push and pop local variables
• there is no need to manage the memory yourself, variables are allocated and freed automatically
• the stack has size limits
• stack variables only exist while the function that created them, is running
The Heap
The heap is a region of your computer's memory that is not managed automatically for you, and is not as tightly
managed by the CPU. It is a more free-floating region of memory (and is larger). To allocate memory on the
heap, you must use malloc() or calloc(), which are built-in C functions. Once you have allocated memory on the
heap, you are responsible for using free() to deallocate that memory once you don't need it any more. If you fail
to do this, your program will have what is known as a memory leak. That is, memory on the heap will still be set
aside (and won't be available to other processes). As we will see in the debugging section, there is a tool
called valgrind that can help you detect memory leaks.
Unlike the stack, the heap does not have size restrictions on variable size (apart from the obvious physical
limitations of your computer). Heap memory is slightly slower to be read from and written to, because one has
to use pointers to access memory on the heap. We will talk about pointers shortly.
Unlike the stack, variables created on the heap are accessible by any function, anywhere in your program. Heap
variables are essentially global in scope.
Stack
Heap
Examples
Here is a short program that creates its variables on the stack. It looks like the other programs we have seen so
far.
P a g e | 20
#include <stdio.h>
return twice;
return 0;
On lines 10, 11 and 12 we declare variables: an int, a double, and an array of three doubles. These three
variables are pushed onto the stack as soon as the main() function allocates them. When the main() function
exits (and the program stops) these variables are popped off of the stack. Similarly, in the
function multiplyByTwo(), the twice variable, which is a double, is pushed onto the stack as soon as
the multiplyByTwo() function allocates it. As soon as the multiplyByTwo() function exits, the twice variable is
popped off of the stack, and is gone forever.
P a g e | 21
As a side note, there is a way to tell C to keep a stack variable around, even after its creator function exits, and
that is to use the static keyword when declaring the variable. A variable declared with the static keyword thus
becomes something like a global variable, but one that is only visible inside the function that created it. It's a
strange construction, one that you probably won't need except under very specific circumstances.
Here is another version of this program that allocates all of its variables on the heap instead of the stack:
#include <stdio.h>
#include <stdlib.h>
return twice;
*age = 30;
*salary = 12345.67;
myList[0] = 1.2;
myList[1] = 2.3;
myList[2] = 3.4;
P a g e | 22
double *twiceSalary = multiplyByTwo(salary);
free(age);
free(salary);
free(myList);
free(twiceSalary);
return 0;
As you can see, using malloc() to allocate memory on the heap and then using free() to deallocate it, is no big
deal, but is a bit cumbersome. The other thing to notice is that there are a bunch of star symbols * all over the
place now. What are those? The answer is, they are pointers. The malloc() (and calloc() and free()) functions
deal with pointers not actual values. We will talk more about pointers shortly. The bottom line though: pointers
are a special data type in C that store addresses in memory instead of storing actual values. Thus on line 5
above, the twice variable is not a double, but is a pointer to a double. It's an address in memory where
the double is stored.
When should you use the heap, and when should you use the stack? If you need to allocate a large block of
memory (e.g. a large array, or a big struct), and you need to keep that variable around a long time (like a
global), then you should allocate it on the heap. If you are dealing with relatively small variables that only need
to persist as long as the function using them is alive, then you should use the stack, it's easier and faster. If you
need variables like arrays and structs that can change size dynamically (e.g. arrays that can grow or shrink as
needed) then you will likely need to allocate them on the heap, and use dynamic memory allocation functions
like malloc(), calloc(), realloc() and free() to manage that memory "by hand". We will talk about dynamically
allocated data structures after we talk about pointers.
Push(S,x)
if Stack-Full(S)
then error "overflow"
else top(S) = top(S) + 1
S[top(S)] = x
Pop(S)
if Stack-Empty(S)
then error "underflow"
else top(S) = top(S) - 1
return S[top(S) + 1]
Stack-Empty(S)
if top(S) = 0
then return True
else return False
Stack-Full(S)
if top(S) = length(S)
then return True
else return False
Stack Java
Below is the syntax highlighted version of Stack.java from §4.3 Stacks and Queues.
/******************************************************************************
* Compilation: javac Stack.java
* Execution: java Stack < input.txt
* Data files: https://introcs.cs.princeton.edu/java/43stack/tobe.txt
*
* A generic stack, implemented using a linked list. Each stack
* element is of type Item.
*
* % more tobe.txt
* to be or not to - be - - that - - - is
*
* % java Stack < tobe.txt
* to be not that or be (2 left on stack)
*
******************************************************************************/
P a g e | 24
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* The {@code Stack} class represents a last-in-first-out (LIFO) stack of generic items.
* It supports the usual <em>push</em> and <em>pop</em> operations, along with methods
* for peeking at the top item, testing if the stack is empty, getting the number of
* items in the stack, and iterating over the items in LIFO order.
* <p>
* This implementation uses a singly-linked list with a nested class for
* linked-list nodes.
* The <em>push</em>, <em>pop</em>, <em>peek</em>, <em>size</em>, and <em>is-empty</em>
* operations all take constant time in the worst case.
* <p>
* For additional documentation,
* see <a href="https://introcs.cs.princeton.edu/43stack">Section 4.3</a> of
* <i>Computer Science: An Interdisciplinary Approach</i>
* by Robert Sedgewick and Kevin Wayne.
*
* @author Robert Sedgewick
* @author Kevin Wayne
*
* @param <Item> the generic type of an item in this stack
*/
public class Stack<Item> implements Iterable<Item> {
private int n; // size of the stack
private Node first; // top of stack
/**
* Initializes an empty stack.
*/
public Stack() {
first = null;
n = 0;
}
/**
* Returns true if this stack is empty.
*
* @return true if this stack is empty; false otherwise
*/
public boolean isEmpty() {
P a g e | 25
return first == null;
}
/**
* Returns the number of items in this stack.
*
* @return the number of items in this stack
*/
public int size() {
return n;
}
/**
* Adds the item to this stack.
*
* @param item the item to add
*/
public void push(Item item) {
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
n++;
}
/**
* Removes and returns the item most recently added to this stack.
*
* @return the item most recently added
* @throws NoSuchElementException if this stack is empty
*/
public Item pop() {
if (isEmpty()) throw new NoSuchElementException("Stack underflow");
Item item = first.item; // save item to return
first = first.next; // delete first node
n--;
return item; // return the saved item
}
/**
* Returns (but does not remove) the item most recently added to this stack.
*
* @return the item most recently added to this stack
* @throws NoSuchElementException if this stack is empty
*/
public Item peek() {
if (isEmpty()) throw new NoSuchElementException("Stack underflow");
return first.item;
P a g e | 26
}
/**
* Returns a string representation of this stack.
*
* @return the sequence of items in this stack in LIFO order, separated by spaces
*/
public String toString() {
StringBuilder s = new StringBuilder();
for (Item item : this) {
s.append(item);
s.append(' ');
}
return s.toString();
}
/**
* Returns an iterator to this stack that iterates through the items in LIFO order.
*
* @return an iterator to this stack that iterates through the items in LIFO order
*/
public Iterator<Item> iterator() { return new ListIterator(); }
/**
* Unit tests the {@code Stack} data type.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {
Stack<String> stack = new Stack<String>();
while (!StdIn.isEmpty()) {
String item = StdIn.readString();
if (!item.equals("-")) stack.push(item);
P a g e | 27
else if (!stack.isEmpty()) StdOut.print(stack.pop() + " ");
}
StdOut.println("(" + stack.size() + " left on stack)");
}
}
Assume we have a stack of size 3 which holds integers between -100 and 100. Here is a series of operations,
and the results.
P a g e | 28
Stacks are a type of container adaptors with LIFO(Last In First Out) type of working, where a new element is
added at one end and (top) an element is removed from that end only.
stack::push()
push() function is used to insert an element at the top of the stack. The element is added to the stack container
and the size of the stack is increased by 1.
Syntax :
stackname.push(value)
Parameters :
The value of the element to be inserted is passed as the parameter.
Result :
Adds an element of value same as that of
the parameter passed at the top of the stack.
Examples:
Input : mystack
mystack.push(6);
Output : 6
Input : mystack
mystack.push(0);
mystack.push(1);
Output : 0, 1
Errors and Exceptions
1. Shows error if the value passed doesn’t match the stack type.
2. Shows no exception throw guarantee if the parameter doesn’t throw any exception.
#include <iostream>
#include <stack>
int main()
P a g e | 29
// Empty stack
stack<int> mystack;
mystack.push(0);
mystack.push(1);
mystack.push(2);
while (!mystack.empty()) {
mystack.pop();
Output:
210
Note that output is printed on the basis of LIFO property
stack::pop()
pop() function is used to remove an element from the top of the stack(newest element in the stack). The
element is removed to the stack container and the size of the stack is decreased by 1.
Syntax :
stackname.pop()
Parameters :
No parameters are passed.
Result :
Removes the newest element in the stack
or basically the top element.
Examples:
Input : mystack = 0, 1, 2
mystack.pop();
Output : 0, 1
Input : mystack = 0, 1, 2, 3, 4, 5
mystack.pop();
Output : 0, 1, 2, 3, 4
Errors and Exceptions
P a g e | 30
1. Shows error if a parameter is passed.
2. Shows no exception throw guarantee.
#include <iostream>
#include <stack>
int main()
stack<int> mystack;
mystack.push(1);
mystack.push(2);
mystack.push(3);
mystack.push(4);
// Stack becomes 1, 2, 3, 4
mystack.pop();
mystack.pop();
// Stack becomes 1, 2
while (!mystack.empty()) {
mystack.pop();
Output:
21
Note that output is printed on the basis of LIFO property
P a g e | 31
Application :
Given a number of integers, add them to the stack and find the size of the stack without using size function.
Input : 5, 13, 0, 9, 4
Output: 5
Algorithm
1. Push the given elements to the stack container one by one.
2. Keep popping the elements of stack until it becomes empty, and increment the counter variable.
3. Print the counter variable.
#include <iostream>
#include <stack>
int main()
int c = 0;
// Empty stack
stack<int> mystack;
mystack.push(5);
mystack.push(13);
mystack.push(0);
mystack.push(9);
mystack.push(4);
while (!mystack.empty()) {
mystack.pop();
c++;
P a g e | 32
cout << c;
P a g e | 33
Reference
1.Wikipedia.org (2019) Shortest path problem [online] Available at :
https://en.wikipedia.org/wiki/Shortest_path_problem [Accessed 14/12/2019]
2. geeksforgeeks.org (2019) stack push() and pop() in C++ STL [online] Available at :
https://www.geeksforgeeks.org/stack-push-and-pop-in-c-stl/ [Accessed 14/12/2019]
P a g e | 34