R24 (Au) Ads Unit-I
R24 (Au) Ads Unit-I
of AI
Sem
UNIT-I
Data structure is a method of organizing a large amount of data more efficiently so that
any operation on that data becomes easy.
OR
Data Structure can be defined as the group of data elements which provides an
efficient way of storing and organizing data in the computer so that it can be used
efficiently.
Non-Primitive Data structure: The non-primitive data structure is divided into two types:
Linear Data Structure: The arrangement of data in a sequential manner is known as a linear
data structure. The data structures used for this purpose are Arrays, Linked list, Stacks, and
Queues. In these data structures, one element is connected to onlyone another element in a
linear form.
Non-Linear Data Structure: When one element is connected to the 'n' number of elements
known as a non-linear data structure. The best example is trees and graphs. In this case, the
elements are arranged in a random manner.
In static memory allocation, the memory In dynamic memory allocation, while executing a
3 cannot be changed while executing a program. program, the memory can be changed.
Static memory allocation is less efficient as Dynamic memory allocation is more efficient as
8 compared to Dynamic memory allocation. compared to the Static memory allocation.
➢ push( ): When we insert an element in a stack then the operation is known as a push. If the stack is
full then the overflow condition occurs.
➢ pop( ): When we delete an element from the stack, the operation is known as a pop. If the stack is
empty means that no element exists in the stack, this state is known as an underflow state.
➢ isEmpty( ): It determines whether the stack is empty or not.
➢ isFull( ): It determines whether the stack is full or not.'
➢ peek( ): It returns the element at the given position.
➢ display( ): It prints all the elements available in the stack
PUSH operation
Push operation: Adding an element into the top of the stack is referred to as push operation.
Push operation involves following two steps.
1. Increment the variable Top so that it can now refer to the next memory location.
2. Add element at the position of incremented top. This is referred to as adding new
element atthe top of the stack.
Stack is overflow when we try to insert an element into a completely filled stack therefore, our
main function must always avoid stack overflow condition.
Algorithm:
1. begin
2. if top = n then stack full
3. top = top + 1
4. stack (top) : = item;
5. end
Time Complexity: O(1)
Pop operation: Deletion of an element from the top of the stack is called pop operation. The
value of the variable top will be incremented by 1 whenever an item is deleted from the stack.
The top most element of the stack is stored in an another variable and then the top is
Algorithm:
1. begin
2. if top = 0 then stack empty;
3. item := stack(top);
4. top = top - 1;
5. end;
Time Complexity: O(1)
Peek operation: Peek operation involves returning the element which is present at the top of
the stack without deleting it. Underflow condition can occur if we try to return the top
element in an alreadyempty stack.
Algorithm:
PEEK (STACK, TOP)
1. Begin
2. if top = -1 then stack empty
3. item = stack[top]
4. return item
5. End
Time complexity: O(n)
isEmpty Operation
Returns true if the stack is empty, else false.
Algorithm for isEmpty Operation:
• Check for the value of top in stack.
• If (top == -1), then the stack is empty so return true .
• Otherwise, the stack is not empty so return false .
isFull Operation
Returns true if the stack is full, else false.
Algorithm for isFull Operation:
• Check for the value of top in stack.
• If (top == capacity-1), then the stack is full so return true.
• Otherwise, the stack is not full so return false.
1. Expression Evaluations & Conversions: A stack is a very effective data structure for
evaluating arithmetic expressions in programming languages. An arithmetic expression
consists of operands and operators.
2. Backtracking(Recursion): Backtracking is another application of Stack. It is a recursive
algorithm that is used for solving the optimization problem.
3. Parsing (Delimiter Checking) : The common application of Stack is delimiter checking, i.e.,
parsing that involves analyzing a source program syntactically. It is also called parenthesis
checking.
4. Function calls: Stacks are used to keep track of the return addresses of function calls,
allowing the program to return to the correct location after a function has finished
executing.
5. Editors: Undo and Redo functions in any text editor.
6. Tree Traversals: Stacks are useful for Depth First Search Traversal method.
7. Browsers: Stacks are useful for function calls, storing the activation records. The history of a
web browser is stored in the form of a stack.
1. Infix Expression
2. Postfix Expression
3. Prefix Expression
Infix Expression:
➢ In infix expression, operator is used in between the operands.
➢ The general structure of an Infix expression is as follows...
Postfix Expression:
➢ In postfix expression, operator is used after operands. We can say that "Operator follows
the Operands".
Prefix Expression:
➢ In prefix expression, operator is used before operands. We can say that "Operands
follows the Operator".
➢ The general structure of Prefix expression is as follows...
Operator Operand1 Operand2
Example:
❖ Every expression can be represented using all the above three different types of expressions.
And we can convert an expression from one form to another form like Infix to Postfix, Infix to
Prefix, Prefix to Postfix and vice versa.
ii) 2 + 3 * 4 – 5 => 2 + (3 * 4) - 5
= (2 + 12) – 5
= (14 – 5)
=9
iii) 2 * 6 /2 – 3 + 7 => (2 * 6) / 2 – 3 + 7
= (12 / 2) – 3 + 7
= (6 – 3) + 7
= (3 + 7)
= 10
iv) 2 * 3 + 5 * 4 – 9 => (2 * 3) + 5 * 4 – 9
= (6) + (5*4) – 9
= (6) + (20) – 9
= (6 + 20) – 9
= (26) – 9
= (26 – 9)
= 17
M.NAGARAJU (Assistant Professor) 9
R24 II B.Tech – I Advanced Data Structures Dept. of AI
Sem
Representation of infix to Prefix Expression (Polish notation) using stack
Example
A + B * C – D => A + ( * B C ) – D
(+A*BC)–D
(-+A*BCD)
-+A*BCD
Algorithm:
1. First, reverse the infix expression given in the problem. While reversing each ‘( ‘will
become ‘)’ and each ‘)’ becomes ‘(‘.
2. Scan the expression from left to right. Whenever the operands arrive, print them.
3. If the operator arrives and the stack is found to be empty, then simply push the
operator into the stack.
4. If the operator is '(', then push it into the stack. If the operator is ')', then pop all the
operators from the stack till it finds ( opening bracket in the stack.
5. If the incoming operator has higher precedence and same precedence with the
TOP of the stack, push the incoming operator into the stack.
6. If the incoming operator has lower precedence than the TOP of the stack, pop, and
print the top of the stack. Test the incoming operator against the top of the stack .
7. When we reach the end of the expression, pop, and print all the operators from the
top of the stack.
8. If the top of the stack is '(', push the operator on the stack.
9. At the end, reverse the output
Example:01- A + B * C – D
➢ If we are converting the expression from infix to prefix, we need first to reverse the
expression.
➢ The Reverse expression would be: D-C*B+A
The above expression, i.e., CB*A+, is not a final expression. We need to reverse this expression to
obtain the prefix expression.
Now infix expression is +A*BC
char stack[MAX];
int top = -1;
void push(char c) {
if (top < MAX - 1) {
stack[++top] = c;
}
}
char pop() {
if (top == -1) return -1;
return stack[top--];
}
int precedence(char c) {
switch (c) {
case '^': return 3;
case '*':
case '/': return 2;
case '+':
case '-': return 1;
default: return -1;
}
}
void reverse(char *exp) {
int len = strlen(exp);
for (int i = 0; i < len/2; i++) {
char temp = exp[i];
exp[i] = exp[len - i -1];
exp[len - i -1] = temp;
}
}
void infixToPostfix(char* infix, char* postfix) {
int i, k = 0;
for (i = 0; infix[i]; i++) {
char c = infix[i];
if (isalnum(c)) {
postfix[k++] = c;
} else if (c == '(') {
push(c);
} else if (c == ')') {
while (top != -1 && peek() != '(') {
postfix[k++] = pop();
}
pop(); // Remove '('
int main() {
char infix[MAX], prefix[MAX];
OUTPUT:
Infix Expression: a*(b+c/d)-e/f
Prefix Expression: -*a+b/cd/ef
1. Read all the symbols one by one from left to right in the given Infix Expression.
2. If the reading symbol is operand, then directly print it to the result (Output).
3. If the reading symbol is left parenthesis '(', then Push it on to the Stack.
4. If the reading symbol is right parenthesis ‘)’, pop the stack and print the operators
until left parenthesis is found.
5. if the reading symbol is the operator and the Stack is empty or contains the '(', ')'
symbol, push the operator into the Stack.
6. If incoming symbol has higher precedence than the top of the stack, push it on
the stack
7. If incoming symbol has lower precedence than the top of the stack, pop and
print the top. Then test the incoming operator against the new top of the stack.
8. If incoming operator has equal precedence with the top of the stack, use
associatively rule
✓ If associatively L to R then pop and prints the top of the stack and then
push the incoming operator.
✓ If associatively R to L then push the incoming operator
9. At the end of the expression, pop and print all operators of stack.
NOTE:
• +,- operators has same precedence
char stack[100];
int top = -1;
void push(char x)
{
stack[++top] = x;
}
char pop()
{
if(top == -1)
return -1;
else
return stack[top--];
}
int priority(char x)
{
if(x == '(')
return 0;
if(x == '+' || x == '-')
return 1;
if(x == '*' || x == '/')
return 2;
return 0;
}
int main()
{
char exp[100];
char *e, x;
printf("Enter the Infix expression : "); scanf("%s",exp);
M.NAGARAJU (Assistant Professor) 17
R24 II B.Tech – I Advanced Data Structures Dept. of AI
Sem
printf("\n");
printf("Postfix express is : ");
e = exp;
while(*e != '\0')
{
if(isalnum(*e))
printf("%c ",*e);
else if(*e == '(')
push(*e);
else if(*e == ')')
{
while((x = pop()) != '(')
printf("%c ", x);
}
else
{
while(priority(stack[top]) >= priority(*e)) printf("%c ",pop());
push(*e);
}
e++;
}
while(top != -1)
{
printf("%c ",pop());
}
return 0;
}
OUTPUT:
Example:01
i) 4 + 6 * 2 = > 4 + (6 2 *)
= ( 4 6 2 * +)
=462*+
Pop( )->A=2 Pop( ) ->A=12
Empty Push(4) Push(6) Push(2) Pop( )->B=6 Push(12) Pop( ) ->B=4 Push(16)
B*A = 6*2=12 B+A = 4+12=16
2
6 6 12
4 4 4 4 4 16
Stack
Therefore, the final answer of postfix notation 4 6 2 * + is 16
ii) 2 + 3 * 4 – 5 => 2 + (3 4 *) - 5
= (2 3 4 * +) – 5
= (2 3 4 5 * + -)
=234*+5–
iii) 2 * 6 /2 – 3 + 7 => (2 6 *) / 2 – 3 + 7
=(26*2/)–3+7
= (2 6 * 2 / 3 -) + 7
= (2 6 * 2 / 3 - 7 +)
=26*2/3–7+
Example-02- (5+3)*(8-2)
#include <stdio.h>
// Recursive function to solve Tower of Hanoi
void TH(int n, char source, char auxiliary, char destination) {
if (n == 1) {
printf("Move disk 1 from %c to %c\n", source, destination);
return;
}
// Move n-1 disks from source to auxiliary
TH(n - 1, source, destination, auxiliary);
// Move the nth disk from source to destination
printf("Move disk %d from %c to %c\n", n, source, destination);
// Move n-1 disks from auxiliary to destination
TH(n - 1, auxiliary, source, destination);
}
int main() {
int n;
printf("Enter number of disks: ");
scanf("%d", &n);
// Call the function with Source = A, Auxiliary = B, Destination = C
TH(n, 'A', 'B', 'C');
return 0;
}
Suppose expression is 2 * ( 6 + 5 )
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Main function
int main() {
char text[MAX_SIZE];
printf("Input an expression in parentheses: ");
scanf("%s", text);
Tree is a non-linear data structure which organizes data in hierarchical structure and this is a
recursive definition.
A tree is a finite set of nodes together with a finite set of directed edges (links/branches) that define
parent-child (HIERARCHICAL) relationships. Tree isa non-linear data structure
Example:
Terminology:
In a tree data structure, we use the following terminology...
1. Root: Root:
2. Edge:
• In a tree data structure, the connecting
link between any two nodes is called as
EDGE.
• In a tree with 'N' number of nodes there
will be a maximum of 'N-1' number of
edges.
4. Child:
• In a tree data structure, the node which
is descendant of any node is called
as CHILD Node.
• In simple words, the node which has a
link from its parent node is called as
child node.
• In a tree, any parent node can have any
number of child nodes.
• In a tree, all the nodes except root are
child nodes.
5. Leaf:
• In a tree data structure, the node which
does not have a child is called as LEAF
Node.
• In simple words, a leaf is a node with no
child.
• In a tree data structure, the leaf nodes are
also called as External Nodes.
• External node is also a node with no child.
• In a tree, leaf node is also called as
'Terminal' node.
6. Siblings:
• In a tree data structure, nodes which
belong to same Parent are called
as SIBLINGS.
• In simple words, the nodes with the
same parent are called Sibling nodes.
7 Internal Nodes:
• In a tree data structure, the node which
has at least one child is called
as INTERNAL Node.
• In simple words, an internal node is a
node with at least one child.
• In a tree data structure, nodes other than
leaf nodes are called as Internal Nodes.
• The root node is also said to be
Internal Node if the tree has more than
one node. Internal nodes are also called as
'Non-Terminal' nodes.
8. Degree:
• In a tree data structure, the total number
of children of a node is called
as DEGREE of that Node.
• In simple words, the Degree of a node is
total number of children it has.
• The highest degree of a node among all
the nodes in a tree is called as 'Degree of
Tree'.
9. Level:
• In a tree data structure, the root node is said
to be at Level 0 and the children of root node
are at Level 1 and the children of the nodes
which are at Level 1 will be at Level 2 and so
on...
• In simple words, in a tree each step from top
to bottom is called as a Level and the Level
count starts with '0' and incremented by one
at each level (Step).
10. Height:
• In a tree data structure, the total number
of edges from leaf node to a particular
node in the longest path is called
as HEIGHT of that Node.
11. Depth:
• In a tree data structure, the total number
of edges from root node to a particular
node is called as DEPTH of that Node.
• In simple words, the highest depth of any
leaf node in a tree is said to be depth of
that tree. In a tree, depth of the root
node is '0'.
12. Path:
• In a tree data structure, the sequence of
Nodes and Edges from one node to
another node is called as PATH between
those two Nodes.
• Length of a Path is total number of nodes
in that path. In below example the path
A - B - E - J has length 4.
A tree in which every node can have a maximum of two children is called Binary Tree.
In a binary tree, every node can have either 0 children or 1 child or 2 children but not more than 2
children.
Example:
A binary tree in which every node has either two or zero number of children is called
Strictly Binary Tree
Strictly binary tree is also called as Full Binary Tree or Proper Binary Tree or 2-Tree
➢ In complete binary tree all the nodes must have exactly two children (except the last level)
and at every level of complete binary tree there must be 2level number of nodes.
➢ For example at level 2 there must be 22 = 4 nodes and at level 3 there must be 23 = 8 nodes.
A complete binary tree is a binary tree in which every level is completely filled except
possibly the last level. In the unfilled level, the nodes are attached starting from the left-
most position
Ex:1 Ex:2
A perfect binary tree is a binary tree in which all interior nodes have two children and all
leaves have the same depth or same level.
Ex:1 Ex:2
In above figure, a normal binary tree is converted into full binary tree by adding dummy nodes (In
pink colour).
The degenerate binary tree is a tree in which all the internal nodes have only one children.
Ex:-1 Ex:-2
right-skewed left-skewed
➢ The above Ex-1 tree is a degenerate binary tree because all the nodes have only one child. It is
also known as a right-skewed tree as all the nodes have a right child only.
➢ The above Ex-2 tree is also a degenerate binary tree because all the nodes have only one child.
It is also known as a left-skewed tree as all the nodes have a left child only.
Example-1:
1 2 3 4 5 6 7
A B C D E F G
Array representation
Example-2:
1 2 3 4 5 6 7
A B C D ---- ----- G
Example:1
The above example of the binary tree represented using Linked list representation is
shown as follows...
The above example of the binary tree represented using Linked list representation is
shown as follows...
Advantages:
➢ Dynamic data storage: it can grow and shrink at runtime by allocating and deallocating
memory.
➢ No Memory Wastage: Efficient memory utilization can be achieved since the size of the
linked list increase or decrease at runtime.
➢ Insertion and Deletion operation: Insertion and deletion operations are quite easier in the
linked list. There is no need to shift elements after the insertion or deletion of an element
only the address present in the next pointer needs to be update.
Disadvantages:
➢ Memory Usage: Extra memory is required in the linked list as compared to an array.
Because in a linked list, a pointer is also required to store the address of the next element
and it require extra memory for itself.
➢ Traversal: Direct or random accessing to an element is not possible in a linked list due to its
dynamic memory allocation. That means extra memory is used for pointers with every
element
that binary tree must be displayed. In any binary tree, displaying order of nodes depends on the
traversal method.
Displaying (or) visiting order of nodes in a binary tree is called as Binary Tree Traversal.
In this method, the left sub-tree (node) is visited first, and then the ROOT node is visited and
later to visited the right sub-tree (node). If a binary tree is traversed in-order, the output will
produce sorted key values in an ascending order. We should always remember that every node
may represent a sub-tree itself.
Algorithm:
Example-1:
In this method, the ROOT node is visited first, and then the left sub-tree (node) is visited
and later to visited the right sub-tree (node).
ROOT node →Left Sub-tree (node)→ Right Sub-tree (node)
Algorithm:
Example-1:
A→ B → D→ E→ C→ F→ G
Example-2:
Algorithm:
Example-1:
➔ We start from A, and following post-order traversal.
➔ We move to its left sub-tree first; that is B.
➔ B is also traversed post-order.
➔ The process goes on until all nodes are visited.
Practice Examples:
➢ In - Order Traversal : B, D, A, G, E, C, H, F, I.
➢ Pre - Order Traversal : A, B, D, C, E, G, F, H, I
➢ Post - Order Traversal: D, B, G, E, H, I, F, C, A
Algorithm:
Example-1: To Construct a binary tree using the following In-order and Post-order traversal of
the binary tree:
Example-2: To Construct a binary tree using the following In-order and Post-order traversals of
the binary tree:
Example:3
Inorder Traversal: [4, 2, 5, 1, 3]
Postorder Traversal: [4, 5, 2, 3, 1]
Algorithm:
1. Find the root node using the pre-order traversal.
2. Find the left sub trees and the right sub trees using in-order traversal by finding the
index of the root node of respective sub trees.
3. Once the root node is found, we can recurse down on the left and right sub trees, i.e.,
left sub array, and right sub array split at respective root index to repeat the same
process until we find at most a single element in either sub-array
Inorder: 2-3-4-5-6-8-10
Preorder: 5-3-2-4-8-6-10
• As we know that preorder visits the root node first then the first value always represents
the root of the tree. From above sequence 5 is the root of the tree.
Preorder
5 -3-2-4-8-6-10
• From above inorder traversal, we know that a node’s left subtree is traversed before it
followed by its right subtree. Therefore, all values to the left of 5 in inorder belong to its left
subtree and all values to the right belong to its right subtree.
Inorder
2-3-4 ← 5 → 6-8-10
So, in this way we constructed the original tree from given preorder and inorder travers
Example:2: Construct binary tree for given postorder and inorder traversals.
Example:3 Construct binary tree for given postorder and inorder traversals.
#include <stdio.h>
#include <stdlib.h>
// Define the structure for a node
struct Node {
int data;
struct Node* left;
struct Node* right;
};
if (data == -1)
return NULL;
return root;
}
return 0;
}
Input format
"First you must give the root element, followed by left and right element of each node in level
order. If a left or right element is not present, enter -1."
For Example consider above Example-3:
INPUT:
Create binary tree:
Enter node value (-1 for no node): 23
Enter left child of 23
Enter node value (-1 for no node): 4
Enter left child of 4
Enter node value (-1 for no node): 1
1. What role does a stack play in the implementation of the Towers of Hanoi problem?
2. Why is a stack used in a parenthesis checker program?
3. In infix to postfix conversion, when do you pop operators from the stack?
4. What is the key difference between infix and prefix expressions regarding operator
placement?
5. How does a stack assist in converting infix expressions to prefix?
6. What is a binary tree? Define a complete binary tree.
7. What is a full binary tree?
8. What is the difference between a full and a complete binary tree
9. How is a binary tree represented using arrays?
10. What are the advantages of array representation of binary trees?
11. What are the disadvantages of array representation of binary trees?
12. How is a binary tree represented using linked lists?
13. What are the advantages of linked list representation in trees?
14. What is tree traversal and why is it needed?
15. Describe inorder traversal of a binary tree.
1. A recursive puzzle is to be solved where disks need to be moved from a source rod to a
destination rod, following the Towers of Hanoi rules.
a) Explain how the recursive solution to the Towers of Hanoi problem works in C?
b) Describe the role of the stack in each recursive call.
2. A program must verify whether mathematical or logical expressions have balanced and
properly nested parentheses before evaluation
a) Discuss how stack operations help check for balanced parentheses in an expression.
b) Write a C program to implement this logic and explain how the stack is updated with
each character in the expression.
3. You are working on a symbolic mathematics tool that takes user input in infix form and
converts it to prefix for faster computation by the backend parser.
a) Explain how stacks can be used to convert an infix expression to prefix in C.
b) Describe the precedence and associativity rules applied during conversion.
c) Provide and explain a C implementation of the algorithm.