ADT in DS
ADT in DS
The above figure shows the ADT model. There are two types of modules in
the ADT model, i.e., the public function and the private function. The ADT
model also contains the data structures that we are using in a program. In this
model, first encapsulation is performed, i.e., all the data is wrapped in a single
unit, i.e., ADT. Then, the abstraction is performed means showing the
operations that can be performed on the data structure and what are the data
structures that we are using in a program.
Let's understand the abstract data type with a real-world example.
If we consider the smartphone. We look at the high specifications of the
smartphone, such as:
o 4 GB RAM
o Snapdragon 2.2ghz processor
o 5 inch LCD screen
o Dual camera
o Android 8.0
The above specifications of the smartphone are the data, and we can also
perform the following operations on the smartphone:
o call(): We can call through the smartphone.
o text(): We can text a message.
o photo(): We can click a photo.
o video(): We can also make a video.
The smartphone is an entity whose data or specifications and operations are
given above. The abstract/logical view and operations are the abstract or
logical views of a smartphone.
The implementation view of the above abstract/logical view is given below:
class Smartphone
{
private:
int ramSize;
string processorName;
float screenSize;
int cameraCount;
string androidVersion;
public:
void call();
void text();
void photo();
void video();
}
The above code is the implementation of the specifications and operations that
can be performed on the smartphone. The implementation view can differ
because the syntax of programming languages is different, but the
abstract/logical view of the data structure would remain the same. Therefore,
we can say that the abstract/logical view is independent of the
implementation view.
Note: We know the operations that can be performed on the predefined data
types such as int, float, char, etc., but we don't know the implementation
details of the data types. Therefore, we can say that the abstract data type is
considered as the hidden box that hides all the internal details of the data type.
Data structure example
Suppose we have an index array of size 4. We have an index location starting
from 0, 1, 2, 3. Array is a data structure where the elements are stored in a
contiguous location. The memory address of the first element is 1000, second
element is 1004, third element is 1008, and the fourth element is 1012. Since it
is of integer type so it will occupy 4 bytes and the difference between the
addresses of each element is 4 bytes. The values stored in an array are 10, 20,
30 and 40. These values, index positions and the memory addresses are the
implementations.
The abstract or logical view of the integer array can be stated as:
o It stores a set of elements of integer type.
o It reads the elements by position, i.e., index.
o It modifies the elements by index
o It performs sorting
The implementation view of the integer array:
1. a[4] = {10, 20, 30, 40}
2. cout<< a[2]
3. a[3] = 50
Features of ADT:
Abstract data types (ADTs) are a way of encapsulating data and operations on
that data into a single unit. Some of the key features of ADTs include:
• Abstraction: The user does not need to know the implementation of the
data structure only essentials are provided.
• Better Conceptualization: ADT gives us a better conceptualization of the
real world.
• Robust: The program is robust and has the ability to catch errors.
• Encapsulation: ADTs hide the internal details of the data and provide a
public interface for users to interact with the data. This allows for easier
maintenance and modification of the data structure.
• Data Abstraction: ADTs provide a level of abstraction from the
implementation details of the data. Users only need to know the
operations that can be performed on the data, not how those operations
are implemented.
• Data Structure Independence: ADTs can be implemented using different
data structures, such as arrays or linked lists, without affecting the
functionality of the ADT.
• Information Hiding: ADTs can protect the integrity of the data by
allowing access only to authorized users and operations. This helps
prevent errors and misuse of the data.
• Modularity: ADTs can be combined with other ADTs to form larger,
more complex data structures. This allows for greater flexibility and
modularity in programming.
Overall, ADTs provide a powerful tool for organizing and manipulating data in
a structured and efficient manner.
Abstract data types (ADTs) have several advantages and disadvantages that
should be considered when deciding to use them in software development.
Here are some of the main advantages and disadvantages of using ADTs:
Advantages:
• Encapsulation: ADTs provide a way to encapsulate data and operations
into a single unit, making it easier to manage and modify the data
structure.
• Abstraction: ADTs allow users to work with data structures without
having to know the implementation details, which can simplify
programming and reduce errors.
• Data Structure Independence: ADTs can be implemented using different
data structures, which can make it easier to adapt to changing needs and
requirements.
• Information Hiding: ADTs can protect the integrity of data by controlling
access and preventing unauthorized modifications.
• Modularity: ADTs can be combined with other ADTs to form more
complex data structures, which can increase flexibility and modularity in
programming.
Disadvantages:
• Overhead: Implementing ADTs can add overhead in terms of memory
and processing, which can affect performance.
• Complexity: ADTs can be complex to implement, especially for large and
complex data structures.
• Learning Curve: Using ADTs requires knowledge of their
implementation and usage, which can take time and effort to learn.
• Limited Flexibility: Some ADTs may be limited in their functionality or
may not be suitable for all types of data structures.
• Cost: Implementing ADTs may require additional resources and
investment, which can increase the cost of development.
Conclusion
Understanding Abstract Data Types (ADTs) and User-Defined Data Types
(UDTs) is crucial for effective data modeling and programming. ADTs provide a
high-level view of data operations and behaviors, promoting abstraction and
encapsulation. UDTs, on the other hand, allow programmers to create custom
data types to implement these abstract concepts. By leveraging both ADTs and
UDTs, developers can design robust and flexible data structures, leading to
more organized and maintainable code. For those interested in deepening their
knowledge, exploring further resources on data structures and programming
paradigms is highly recommended.
STACK as an ADT
The abstract datatype is special kind of datatype, whose behavior is defined by
a set of values and set of operations. The keyword “Abstract” is used as we can
use these datatypes, we can perform different operations. But how those
operations are working that is totally hidden from the user. The ADT is made of
with primitive datatypes, but operation logics are hidden.
Here we will see the stack ADT. These are few operations or functions of the
Stack ADT.
• isFull(), This is used to check whether stack is full or not
• isEmpty(), This is used to check whether stack is empty or not
• push(x), This is used to push x into the stack
• pop(), This is used to delete one element from top of the stack
• peek(), This is used to get the top most element of the stack
• size(), this function is used to get number of elements present into the
stack
Example
#include<iostream>
#include<stack>
using namespace std;
main(){
stack<int> stk;
if(stk.empty()){
cout << "Stack is empty" << endl;
} else {
cout << "Stack is not empty" << endl;
}
//insert elements into stack
stk.push(10);
stk.push(20);
stk.push(30);
stk.push(40);
stk.push(50);
cout << "Size of the stack: " << stk.size() << endl;
//pop and dispay elements
while(!stk.empty()){
int item = stk.top(); // same as peek operation
stk.pop();
cout << item << " ";
}
}
Output
Stack is empty
Size of the stack: 5
50 40 30 20 10
Enter choice: 1
Enter value to be pushed: 2
Enter choice: 1
Enter value to be pushed: 6
Enter choice: 1
Enter value to be pushed: 8
Enter choice: 1
Enter value to be pushed: 7
Enter choice: 2
The popped element is 7
Enter choice: 3
Stack elements are:8 6 2
Enter choice: 5
Invalid Choice
Enter choice: 4
Exit
In the above program, the push() function takes argument val i.e., value to be
pushed into the stack. If a top is greater than or equal to n, there is no space in a
stack and overflow is printed. Otherwise, val is pushed into the stack. The code
snippet for this is as follows.
void push(int val) {
if(top>=n-1)
cout<<"Stack Overflow"<<endl;
else {
top++;
stack[top]=val;
}
}
The pop() function pops the topmost value of the stack, if there is any value. If
the stack is empty then underflow is printed. This is given as follows.
void pop() {
if(top<=-1)
cout<<"Stack Underflow"<<endl;
else {
cout<<"The popped element is "<< stack[top] <<endl;
top--;
}
}
The display() function displays all the elements in the stack. It uses a for loop to
do so. If there are no elements in the stack, then Stack is empty is printed. This is
given below.
void display() {
if(top>=0) {
cout<<"Stack elements are:";
for(int i=top; i>=0; i--)
cout<<stack[i]<<" ";
cout<<endl;
}else
cout<<"Stack is empty";
}
The function main() provides a choice to the user if they want to push, pop or
display the stack. According to the user response, the appropriate function is
called using switch. If the user enters an invalid response, then that is printed.
The code snippet for this is given below.
int main() {
int ch, val;
cout<<"1) Push in stack"<<endl;
cout<<"2) Pop from stack"<<endl;
cout<<"3) Display stack"<<endl;
cout<<"4) Exit"<<endl;
do {
cout<<"Enter choice: "<<endl;
cin>>ch;
switch(ch) {
case 1: {
cout<<"Enter value to be pushed:"<<endl;
cin>>val;
push(val);
break;
}
case 2: {
pop();
break;
}
case 3: {
display();
break;
}
case 4: {
cout<<"Exit"<<endl;
break;
}
default: {
cout<<"Invalid Choice"<<endl;
}
}
}while(ch!=4);
return 0;
}
Application of Stack
Expression Conversion:
Infix Expressions
Infix expressions are mathematical expressions where the operator is placed
between its operands. This is the most common mathematical notation used by
humans. For example, the expression "2 + 3" is an infix expression, where the
operator "+" is placed between the operands "2" and "3".
Operator precedence rules:
Infix expressions follow operator precedence rules, which determine the order
in which operators are evaluated. For example, multiplication and division have
higher precedence than addition and subtraction. This means that in the
expression "2 + 3 * 4", the multiplication operation will be performed before the
addition operation.
Here's the table summarizing the operator precedence rules for common
mathematical operators:
Operator Precedence
Parentheses () Highest
Exponents ^ High
Multiplication * Medium
Operator Precedence
Division / Medium
Addition + Low
Subtraction - Low
Postfix Notation
Prefix Notation (Reverse Polish
Infix Notation (Polish Notation) Notation)
Operator Between
Before operands After operands
Placement operands
Parentheses
Often required Not required Not required
Requirement
Required,
Not required, Not required,
Operator parentheses
operators have operators have
Precedence determine
fixed precedence fixed precedence
Tracking precedence
Evaluation
Left-to-right Right-to-left Left-to-right
Method
Common in
Common in Common in
everyday
computer science computer science
arithmetic and
and programming and programming
mathematical
languages languages
Usage notation
Infix to Prefix, Postfix
Prefix and Postfix to Infix
1.infix to prefix
Steps required for infix to prefix conversion using stack in C++
• Initially reverse the expression given for the infix.
• One by one scan of characters.
• Is if character is an operand, then copy it to the output of the prefix
notation.
• When the character is a parenthesis closing then push it to the stack.
• If the character is an opening parenthesis, pop the elements in the stack
till we find the closing parenthesis that corresponds.
• If a character scanned is operator.
• If the operator has greater or equal precedence than the top of the stack,
push the operator to the stack.
• If the operator has less precedence than the top of the stack, pop the
operator and output it to the output of the prefix notation, then check the
above condition with the new top of the stack again.
• After scanning all the characters, reverse the notation output for the
prefix.
C++ Program for Infix To Prefix Conversion using stack data structures: -
#include <bits/stdc++.h> /*Reduces time wastage, Eliminates the need to
write specific header files, Minimizes include statements, and Increases
readability and understandability*/
using namespace std;
//definition of functions
struct Stack *create (int max);
int stackFull (struct Stack *stack);
int stackEmpty (struct Stack *stack);
void pushElement (struct Stack *stack, int item);
int popElement (struct Stack *stack);
int peekElement (struct Stack *stack);
int checkOperand (char ch);
int precedence (char ch);
int postfix (char *expression);
void reverse (char *exp);
void brackets (char *exp);
void conversionInfixToPrefix (char *exp);
// A structure to represent a stack
struct Stack
{
int top;
int maxSize;
int *array;
};
int main ()
{
int n = 10;
cout << "The infix expression is: \n";
char expression[] = "(P+(Q*R)/(S-T))";
cout << expression << "\n";
conversionInfixToPrefix (expression);
cout << "The prefix expression is: \n";
cout << expression;
return 0;
}
//stack implementation
struct Stack * create (int max)
{
struct Stack *stack = (struct Stack *) malloc (sizeof (struct Stack));
stack->maxSize = max;
stack->top = -1;
stack->array = (int *) malloc (stack->maxSize * sizeof (int));
return stack;
}
case '*':
case '/':
return 2;
case '^':
return 3;
}
return -1;
}
//if we scan character we need to pop and print from the stack
else if (expression[i] == ')')
{
while (!stackEmpty (stack) && peekElement (stack) != '(')
expression[++j] = popElement (stack);
if (!stackEmpty (stack) && peekElement (stack) != '(')
return -1; // invalid expression
else
popElement (stack);
}
else // if an operator
{
while (!stackEmpty (stack)
&& precedence (expression[i]) <=
precedence (peekElement (stack)))
expression[++j] = popElement (stack);
pushElement (stack, expression[i]);
}
return 0;
}
temp[j--] = '\0';
while (exp[i] != '\0')
{
temp[j] = exp[i];
j--;
i++;
}
strcpy (exp, temp);
}