Chaitany.S.Kakde DS Assignment BT24S05F007
Chaitany.S.Kakde DS Assignment BT24S05F007
1. Define data structure. List the various linear and non-linear data structures and explain
them in brief.
Data Structure is a specialized format used for organizing, managing, and storing data efficiently. It
allows for the efficient retrieval and modification of data and forms the foundation for designing
algorithms. Data structures help us optimize both time and space complexity for various operations
like searching, sorting, insertion, and deletion.
1. Array:
• Operations:
• Limitation: Fixed size, so you cannot change its size during runtime.
2. Linked List:
• A linked list is a linear collection of elements (nodes), where each node contains data
and a reference (link) to the next node.
• Types: Singly Linked List, Doubly Linked List, Circular Linked List.
• Example: head -> data -> next -> data -> next -> null.
3. Stack:
• A stack follows the Last-In-First-Out (LIFO) principle. Elements are added (pushed)
and removed (popped) from the top of the stack.
• Example: Stack of plates where the last plate added is the first to be removed.
4. Queue:
• A queue follows the First-In-First-Out (FIFO) principle. Elements are added
(enqueued) at the rear and removed (dequeued) from the front.
1. Tree:
• Types: Binary Tree, Binary Search Tree, AVL Tree, N-ary Tree, etc.
2. Graph:
• Example: Social networks, city road maps, web pages and their hyperlinks.
• Operations: Depth First Search (DFS), Breadth First Search (BFS), shortest path
algorithms (Dijkstra, A*).
2. What does abstract data type mean? Briefly explain linear and non-linear data structures.
Abstract Data Type (ADT) is a high-level description of a data structure, defined by its behavior
from the user's point of view, without specifying the implementation details. An ADT provides a
logical description of the data and the operations that can be performed on it, but the internal
representation or storage is hidden.
• Example: A Queue can be defined as an ADT that supports enqueue (add an element) and
dequeue (remove an element) operations. The implementation can vary (e.g., using arrays
or linked lists), but the operations remain the same.
In linear data structures, the primary operations allow you to manage and manipulate the elements
in the structure effectively. Here are the most common operations:
1. Insertion:
• In an array: you can insert an element at any index if there is enough space.
• In a linked list: insert a new node after a specific node (at the beginning, middle, or
end).
2. Deletion:
• In an array: you can remove an element and shift other elements if necessary.
• In a linked list: remove a node by adjusting the pointers (either the previous or next
pointer).
3. Traversal:
• In a linked list, you need to start from the head node and follow the links until you
reach the end.
4. Search:
• In an array, you can use linear search or binary search (if the array is sorted).
• In a linked list, you traverse the list and compare each node’s data until you find the
desired element.
5. Update:
• In an array, you can directly access and modify an element via its index.
• In a linked list, you must traverse the list to find the node and then update its data.
6. Peek/Top:
• In stack and queue operations, you can view the element at the top (stack) or front
(queue) without removing it.
7. Check Empty:
• For example, checking if the top of a stack is NULL or if the front of the queue is
NULL.
Dynamic memory allocation in C allows you to allocate memory at runtime using pointers. This is
especially useful when you don’t know the amount of memory needed beforehand. The following
functions are used for dynamic memory allocation:
1. malloc():
• Returns a pointer to the beginning of the block. If memory allocation fails, it returns
NULL.
sizeof(int));
2. calloc():
• It takes two parameters: the number of elements and the size of each element.
3. realloc():
• The new size is specified, and it returns a pointer to the resized memory block.
4. free():
• Frees up the dynamically allocated memory and releases it back to the system.
• Syntax: free(ptr);
• Example: free(arr);
Using dynamic memory allocation helps in creating flexible programs that can adapt to different
memory requirements at runtime.
Elements are arranged in a sequence. Elements are arranged in a hierarchical or networked structure.
Each element has a predecessor and successor. There is no such direct relationship between elements.
Operations like traversal and searching are simple. Traversal requires more complex algorithms (DFS, BFS).
Best used for simpler problems where data can be Best suited for more complex problems where relationships
sequentially processed. between elements are important.
Stack Queue
Follows LIFO (Last-In, First-Out) order. Follows FIFO (First-In, First-Out) order.
Elements are added and removed from the same end, called Elements are added from the rear and removed from
the top. the front.
Operations: Push, Pop, Peek, IsEmpty. Operations: Enqueue, Dequeue, Peek, IsEmpty.
Uses: Function calls, expression evaluation. Uses: CPU scheduling, managing requests in queues.
(b) Primitive and Non-Primitive Data Structures
Primitive Data Structure Non-Primitive Data Structure
Example: int, char, float, etc. Example: Arrays, Linked Lists, Trees, Graphs, etc.
Simple data types with direct memory allocation. Complex structures requiring additional handling.
Cannot grow or shrink in size after allocation. Can grow or shrink in size during program execution.
More efficient in terms of memory access speed. Provides flexibility in memory usage.
A stack is a linear data structure that follows the Last-In-First-Out (LIFO) principle. The last
element added to the stack is the first one to be removed.
Operations:
Applications:
1. Function calls: The call stack in programming languages is used to manage function calls,
storing local variables and function return addresses.
2. Expression evaluation: Infix, prefix, and postfix expression evaluation use stacks to convert
between different notations.
3. Undo operations: Used in applications like text editors to allow users to undo their previous
actions.
4. Browser history: The stack helps maintain the history of visited pages.
5. Balanced Parentheses: A stack can be used to check whether an expression has balanced
parentheses.
A Queue is a linear data structure that follows the First-In-First-Out (FIFO) principle. The first
element added to the queue will be the first one to be removed. The queue is often likened to a
realworld queue, such as a line at a ticket counter or a queue in a printer's job processing system.
Operations:
3. Front: Returns the front element of the queue without removing it.
4. Rear: Returns the rear element of the queue without removing it.
Applications:
1. Job Scheduling: Operating systems use queues to schedule tasks and processes. The first task
to arrive is the first to be executed.
2. CPU Scheduling: A queue is used to manage processes in the operating system. The
processes are executed in the order they arrive.
3. Breadth-First Search (BFS): In graph traversal, a queue is used to explore nodes level by
level.
4. Printer Queue: When multiple documents are sent to a printer, they are processed in the
order they were added to the queue.
5. Call Center Systems: Incoming calls are placed in a queue, and operators serve them in the
order of arrival.
Elements are arranged in a sequential manner. Elements are not arranged sequentially.
Traversal is simpler, usually from start to end. Traversal is more complex (e.g., DFS, BFS).
A Tree is a hierarchical, non-linear data structure made up of nodes connected by edges. It consists of
a root node, child nodes, and subtrees. Trees are widely used to represent hierarchical structures like
file systems and organizational charts.
Types of Trees:
1. Binary Tree: A tree where each node has at most two children, usually referred to as the left
and right child.
2. Binary Search Tree (BST): A binary tree where for each node, the left child contains values
less than the node, and the right child contains values greater than the node.
3. AVL Tree: A self-balancing binary search tree where the difference in height between the left
and right subtrees of any node is at most one.
4. Heap: A complete binary tree where each parent node is greater than (or less than) its
children, used for implementing priority queues.
5. N-ary Tree: A tree where each node can have at most 'N' children.
Operations:
1. Traversal:
• Inorder: Traverse the left subtree, visit the root, then the right subtree.
• Preorder: Visit the root, then the left and right subtrees.
• Postorder: Traverse the left and right subtrees, then visit the root.
2. Insertion: Insert a node into the tree based on its value (in BSTs, this is done to maintain the
binary search property).
3. Deletion: Remove a node from the tree. In the case of BSTs, it requires ensuring the
properties of the tree are preserved.
4. Searching: Find a node in the tree. In a BST, it can be done more efficiently by comparing
values at each node.
Applications:
1. Hierarchical Data Representation: Trees are used to represent hierarchical data like
organizational charts and folder structures in file systems.
4. Database Indexing: B-trees and B+ trees are used in databases for indexing and searching.
A Graph is a non-linear data structure made up of a set of vertices (nodes) and edges (connections
between the vertices). Graphs are useful for representing complex relationships, such as social
networks, transportation networks, or web page links.
Types of Graphs:
1. Undirected Graph: In this type of graph, the edges do not have a direction. If there is an
edge between two nodes, you can traverse in both directions.
2. Directed Graph (Digraph): In this type of graph, edges have a direction. If there is an edge
from node A to node B, you cannot traverse from B to A unless there is a reverse edge.
3. Weighted Graph: Each edge has a weight (a numerical value), which could represent the
distance, cost, or time to traverse the edge.
4. Unweighted Graph: The edges do not have any weight; they simply represent a connection
between vertices.
5. Cyclic Graph: A graph that contains at least one cycle (a path where the first and last vertex
are the same).
Operations:
1. Traversal:
• Depth-First Search (DFS): Start at the root and explore as far as possible along each
branch before backtracking.
• Breadth-First Search (BFS): Start at the root and explore all neighbors at the present
depth level before moving on to nodes at the next depth level.
3. Shortest Path: Algorithms like Dijkstra's or Bellman-Ford are used to find the shortest path
between two vertices in weighted graphs.
Applications:
1. Social Networks: Graphs can represent social media networks, where users are vertices and
their relationships (like friends, followers) are edges.
2. Routing Algorithms: Graphs are used in network routing protocols and algorithms to find the
best path for data packets in the network.
3. Web Page Link Structure: Graphs represent the hyperlinks between web pages.
1. Bubble Sort:
• Repeatedly steps through the list, compares adjacent items, and swaps them if they
are in the wrong order. This process repeats until the list is sorted.
2. Selection Sort:
• Divides the list into a sorted and unsorted part. The smallest (or largest) element from
the unsorted part is selected and swapped with the first unsorted element. This
process is repeated for the remaining unsorted elements.
3. Insertion Sort:
• Builds the sorted list one item at a time by taking elements from the unsorted part and
inserting them into the correct position in the sorted part.
• Time Complexity: O(n²), but efficient for small datasets or nearly sorted lists.
4. Merge Sort:
• A divide-and-conquer algorithm. It divides the list into two halves, recursively sorts
them, and then merges them back together.
• Time Complexity: O(n log n) • Stable and efficient for large datasets.
5. Quick Sort:
• Time Complexity: O(n log n) (on average), but can degrade to O(n²) in the worst
case.
6. Heap Sort:
• Converts the list into a heap (a binary tree with a specific property), and then sorts it
by repeatedly extracting the maximum (or minimum) element from the heap and
rebuilding the heap. • Time Complexity: O(n log n)
7. Radix Sort:
• Sorts numbers by processing individual digits. It processes digits starting from the
least significant to the most significant (or vice versa).
• Time Complexity: O(nk), where 'k' is the number of digits in the largest number.
8. Counting Sort:
• Works by counting the number of occurrences of each element and then calculates the
position of each element in the sorted output.
Assignment No:02
1. Define Sparse Matrix. Briefly explain representation of sparse matrix with the help of link list
and array.
Sparse Matrix: A sparse matrix is a matrix in which the majority of its elements are zero. In contrast, a
dense matrix has very few zero elements. Sparse matrices are commonly encountered in real-world
problems, such as in graph theory, where most of the elements (edges) are not present. Storing all the
elements of a sparse matrix in a conventional 2D array would be inefficient as it would require
excessive space for zero elements.
Representation: To represent sparse matrices efficiently, we use techniques that store only the nonzero
elements. Two common ways of representing sparse matrices are using arrays and linked lists.
Array Representation:
Triple Array Representation: A sparse matrix can be represented by three arrays: one for row indices,
one for column indices, and one for the values of the non-zero elements.
Format: Each non-zero element is stored as a triplet (row index, column index, value), and these
triplets are stored in an array.
0030
0000
5000
0000
Values: [3, 5]
A more space-efficient way to represent a sparse matrix is by using a singly linked list where each
node stores a non-zero element and its row and column indices.
element).
A linked list of linked lists can be used for storing each row as a separate linked list. This allows
efficient storage and access to non-zero elements.
Example: For the same matrix above, the linked list representation would look something like this:
Row 0: (0, 2, 3)
Row 2: (2, 0, 5)
2. Given a two-dimensional array A1(1:8, 7:14) stored in row-major order with base address 100
and size of each element is 4 bytes, find the address of the element A1(4, 12).
In row-major order, the elements are stored row by row. The formula for the address of an element
A[i][j]A[i][j] in a row-major ordered matrix is:
• i=4i=4, j=12j=12
• The number of rows = 8, the number of columns = 8 (since columns are from 7 to 14)
Address=100+((4−1)×8+(12−7))×4
Address=100+((4−1)×8+(12−7))×4
Address=100+(3×8+5)×4
Address=100+(3×8+5)×4 Address=100+(24+5)×4
Address=100+(24+5)×4
Address=100+29×4
Address=100+29×4
Address=100+116=216
Address=100+116=216
3. Given a two-dimensional array Z1(2:9, 9:18) stored in column-major order with base address
100 and size of each element is 4 bytes, find the address of the element Z1(4, 12).
In column-major order, the elements are stored column by column. The formula for the address of
an element Z[i][j]Z[i][j] in a column-major ordered matrix is:
• i=4i=4, j=12j=12
• The number of rows = 8, the number of columns = 10 (since rows are from 2 to 9 and
columns are from 9 to 18) Now, applying the formula:
Address=100+((12−9)×8+(4−2))×4
Address=100+((12−9)×8+(4−2))×4
Address=100+(3×8+2)×4
Address=100+(3×8+2)×4
Address=100+(24+2)×4
Address=100+(24+2)×4
Address=100+26×4
Address=100+26×4
Address=100+104=204
Address=100+104=204
Stack Questions:
A stack is a linear data structure that follows the Last In, First Out (LIFO) principle. This means the
last element inserted into the stack will be the first one to be removed. Stacks are used in a variety of
applications such as function calls, expression evaluation, and backtracking algorithms.
Basic Operations:
3. Peek (or Top): Returns the top element without removing it.
The peep() function returns the top element of the stack The pop() function removes and returns the top element of the
without removing it. stack.
It allows you to view the top element. It modifies the stack by reducing its size.
Example: If the stack is [5, 10, 15], peep() will return Example: If the stack is [5, 10, 15], pop() will return 15 and the
15. stack will become [5, 10].
peep() does not change the state of the stack. pop() changes the stack by removing the top element.
Used when you only need to check the top element. Used when you need to remove the top element.
peep() pop()
peep() does not raise an underflow error. pop() may raise an underflow error if the stack is empty.
3. Write a C program to implement a stack with all necessary overflow and underflow checks
using array.
#include <stdio.h>
#define MAX 5
top = -1;
int isFull() { return top
== MAX - 1;
int isEmpty()
if (isFull())
{ printf("Stack Overflow\
n");
printf("Stack Underflow\n");
stack[top--];
printf("Stack is empty\n");
stack[top];
}
int main() { push(10); push(20);
1. Algorithm:
3. Pop the characters from the stack and store them in the original string.
#include <stdio.h>
#include <string.h>
char stack[MAX];
+top] = c;
= -1) { return
stack[top--];
return -1; }
{ str[i] = pop();
reverseString(str); printf("Reversed
1. Algorithm:
4. For every closing parenthesis, check if the stack is empty; if it is not, pop the stack.
#include <string.h>
char stack[MAX];
+top] = c;
= -1) { return
stack[top--];
}
return -1;
{ if (expr[i] == '(')
{ push(expr[i]);
0; // Unbalanced
pop();
"(a+b)*(c+d)"; if
(isBalanced(expr))
{ printf("Balanced\n");
} else
{ printf("Unbalanced\n");
return 0;
• GCD(a, b) = GCD(b, a % b)
#include <stdio.h>
return a; else
int main() {
&a, &b);
return 0;
The factorial of a non-negative integer n, denoted as n!, is the product of all positive integers less
than or equal to n. The recursive formula is:
int factorial(int n) { if (n == 0)
- 1);
int main() {
int n;
scanf("%d", &n);
return 0;
8. Enlist difference between recursive and iterative algorithms. Write any one recursive function
showing the stack contents while function call and return.
A function calls itself to solve the The problem is solved using loops (for,
Definition problem. while).
Uses function call stack, leading to Uses a fixed amount of memory, mainly
Memory Usage high memory usage. for variables.
Requires a base case to terminate the Does not require a base case but
Base Case recursion. requires proper loop conditions.
Can have higher overhead due to
Performance multiple function calls. Generally more efficient as it uses loops.
Let's consider the recursive function for factorial, and we'll print the stack contents at each call:
#include <stdio.h>
int factorial(int n) {
9. Write a C user-defined function for Tower of Hanoi for N disks and three towers. Write stack
representation for N=4.
Tower of Hanoi Problem: The goal is to move N disks from the source tower to the destination tower
using an auxiliary tower, following these rules:
2. A disk can only be placed on an empty tower or a tower with a larger disk on top.
#include <stdio.h>
destination);
return;
return 0;
}
Stack Representation for N = 4: Each recursive call represents a function call to move a disk. For N
= 4, the sequence of function calls would look like this:
FIFO is a queue system where the first LIFO is a stack system where the last
Definition element added is the first to be removed. element added is the first to be removed.
Data Structure
Type Queue Stack
Order of First element in is processed first (like a Last element in is processed first (like a
Operations queue at a ticket counter). stack of plates).
Example Queue (e.g., printer queue) Stack (e.g., stack of plates or books)
Data Removal Removed in the order they were added. Removed in reverse order of addition.
Used in scheduling, buffers, and handling Used for function calls, undo operations,
Usage requests. and depth-first search.
12. What is the advantage of Polish expression over infix notation? Write an algorithm to
convert an infix expression into reverse Polish expression.
1. No need for parentheses: In Polish (Prefix) and Reverse Polish (Postfix) notations,
parentheses are not needed to dictate the order of operations. The operator precedence is
inherent in the expression's structure.
2. Easier for computers to evaluate: Reverse Polish notation (RPN) is easy for computers to
evaluate because it removes the need for parsing operator precedence or handling parentheses
during evaluation.
3. Faster computation: Polish and Reverse Polish expressions reduce the computational
overhead by eliminating the need to perform operator precedence and parenthesis evaluation.
We can use Shunting Yard algorithm (created by Edsger Dijkstra) to convert an infix expression to a
postfix (Reverse Polish) expression.
1. Create an empty stack for operators and an empty list for the output.
• While the stack is not empty and the top of the stack has the same or higher
precedence, pop the stack to the output.
• If the token is a right parenthesis, pop operators from the stack to the output until a
left parenthesis is encountered.
4. After reading the input, pop all operators from the stack to the output.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define MAX 100
int precedence(char c) { if (c
char stack[MAX];
char c = infix[i];
else {
precedence
}
stack[top--];
postfix[MAX]; printf("Enter an
infix);
infixToPostfix(infix, postfix);
return 0;
13. Convert the given infix expression to postfix and prefix expression.
1) A + ( (B – C) * (D – E) + F) / G ) $ (H – J)
• Postfix: A B C - D E - * F + G / + H J - $
• Prefix: $ + + A * - B C - D E F / G - H J
2) (A + B) * (C – D) $ E * F
• Postfix: A B + C D - * E F * $
• Prefix: $ * + A B - C D * E F
3) (A + B) * (C ^ (D – E) + F) – G
• Postfix: A B + C D E - ^ F + * G -
• Prefix: - * + A B + ^ C - D E F G
4) A + B * C
• Postfix: A B C * +
• Prefix: + A * B C
5) A + B * C ^ D – E
• Postfix: A B C D ^ * + E -
• Prefix: - + A * B ^ C D E
6) A + [(B + C) + (D + E) * F] / G
• Postfix: A B C + D E + F * + G / +
• Prefix: + A / + + B C * F + D E G
7) (A + B) * C / D + E ^ F / G
• Postfix: A B + C * D / E F ^ G / +
• Prefix: + / * + A B C D ^ E F / G
8) (A + B) * C / D
• Postfix: A B + C * D /
• Prefix: / * + A B C D
9) ((A + B – C / D) / E)
• Postfix: A B + C D / - E /
• Prefix: / - + A B / C D E
10) A / (B – C / D ^ E) + F
• Postfix: A B C D E ^ / - / F +
• Prefix: + / A - B / C ^ D E F
11) A – B / (C * D ^ E)
• Postfix: A B C D E ^ * / -
• Prefix: - A / B * C ^ D E
(5+8):
5+8=13
Answer: 13
2) 4 + 2 * 5 ^ 2 + 9 / 3 – 1 * 8
Then, 9 / 3: 9/3=3
Then, 1 * 8: 1 8 = 8
Now, substitute the results and perform the remaining addition and
subtraction: 4+50+3−8
First, 4 + 50 = 54
Then, 54 + 3 = 57 Finally,
57 - 8 = 49
Answer: 49
3) 40 25 + 20 5 * 3 + *
20 5=100
100+3=103
65 103=6695
4) 9 + 5 * 7 – 6 ^ 2 + 9 / 3
6^2=36
Now, substitute the results and perform the remaining addition and subtraction:
9+35−3
First, 9 + 35 = 44 Then,
44 - 36 = 8
Finally, 8 + 3 = 11
Answer: 11
5) 8 * 2 -1 + 7 * 5
8 * 2: 8 2=16
7 * 5: 7 5=35
Now, substitute the results and perform the remaining addition and
subtraction:
16−1+35
First, 16 - 1 = 15
Then, 15 + 35 = 50
Answer: 50
1) A B + C – B A + C - +
2) A B C + * C B A - + *
1. A B + C – B A + C - +
Substitute ( A = 1 ), ( B = 2 ), and ( C = 3 ):
(12+3-21+3-+)
( 1 + 2 = 3 ) → `3 3 - 2 1 + 3 - +`
( 3 - 3 = 0 ) → `0 2 1 + 3 - +`
( 2 + 1 = 3 ) → `0 3 3 - +`
( 3 - 3 = 0 ) → `0 0 +`
(0+0=0)
Final Result: 0
2.A B C + * C B A - +
Substitute ( A = 1 ), ( B = 2 ), and ( C = 3 ):
(123+*321-+*)
(2+3=5)→15*321-+
( 1 * 5 = 5) → `5 3 2 1 - +
(2-1=1)→531+
(3+1=4)→54*
( 5 * 4 = 20 )
Final Result: 20
Name :Vishal Rajesh Bhutekar
Roll No :BT24S05F002
2. Memory Allocation:
• Array : Arrays have a fixed size that must be defined at the time of their creation, and
memory is allocated in contiguous blocks. This can be a disadvantage if the size of the
array needs to change, as resizing is often costly in terms of time and memory.
• Linked List : Linked Lists use dynamic memory allocation. Each node is allocated
separately, and nodes are linked together using pointers. This means the list can grow or
shrink easily by adding or removing nodes without a need to reallocate a contiguous
memory block.
• Array : Fixed in size; if you need more space, a new array must be created with
additional space, and the existing elements must be copied over. This can be inefficient in
cases of frequent resizing.
• Linked List : Supports dynamic resizing, allowing easy addition and removal of nodes
without worrying about a fixed size. Thus, linked lists are useful when the number of
elements is unknown at the outset or may vary significantly.
• Array : Suitable for applications where fast element access is essential, and the size of the
collection is known in advance (e.g., look-up tables, databases).
• LinkedList : Used in scenarios requiring frequent insertions and deletions (e.g.,
implementation of stacks, queues, and real-time applications).
•.
Algorithm:
Code Example in C :
c
Copy code
#include <stdio.h>
#include
<stdlib.h> struct
Node { int data;
int priority;
struct Node* next;
};
Algorithm:
1. Initialize three pointers: prev (initially NULL), current (points to the head), and next (will
be used to store the next node).
2. Traverse the list. For each node: o Save the next node. o Change the next pointer of
the current node to prev .
o Move prev and current one step forward.
3. Once current becomes NULL (end of the list), prev will be the new head of the reversed
list.
Code Example in C :
Insertion :
1. Find the specified node after which the new node needs to be inserted. 2.
Create a new node, set its next pointer to the next pointer of the specified node. 3.
Update the next pointer of the specified node to point to the new node.
Deletion :
Each function here provides the essential operations for manipulating linked lists,
essential in various applications such as implementing queues, dynamic memory
structures, and real-time systems where fast insertion and deletion are critical.
Brief Explanation:
A polynomial can be represented using a doubly linked list where each node contains the
coefficient and exponent of a term. To add two polynomials, we traverse both lists
simultaneously, comparing the exponents:
1. Representation of a Polynomial:
o Each node in the doubly linked list contains the coefficient and exponent of a
polynomial term.
o For example, 3x2+4x+53x^2 + 4x + 53x2+4x+5 would be represented as three
nodes: (3,2),(4,1),(5,0)(3, 2), (4, 1), (5, 0)(3,2),(4,1),(5,0).
o Using a doubly linked list allows us to traverse the list in both forward and
reverse directions, making it versatile.
2. Adding Two Polynomials:
o Initialization: Start with two pointers, each at the head of one of the polynomial
lists. o Comparison: Compare the exponents of the nodes at both pointers.
▪ If exponents are the same, add the coefficients and create a new node with
the sum.
If exponents differ, add the node with the smaller exponent directly to the
▪
result list.
o Traversal: Move the pointer for the processed term to the next node.
o Edge Cases: If one polynomial has more terms than the other, append the
remaining terms to the result.
3. Necessary Functions:
o Insert Node: To add terms to the result list in the correct order. o Display
Polynomial: To print the resulting polynomial in readable form.
#include <iostream>
using namespace std;
struct Node {
int coeff;
int exp;
Node* next;
Node* prev;
};
Concatenating two doubly linked lists involves linking the last node of the first list to the first
node of the second list. This can be done in constant time if we maintain pointers to the last
node in each list.
Detailed Explanation:
A doubly linked list allows traversal in both directions, providing more flexibility compared to
a singly linked list. Additionally, it allows easy deletion of nodes from both ends, improving the
efficiency of certain operations like reversing and deletion.
Detailed Explanation:
1. Bidirectional Traversal:
o In a doubly linked list, each node contains a pointer to both its next and previous
nodes, allowing traversal in both directions.
o This is particularly useful in applications where both forward and backward
traversal are needed (e.g., in browser history, where users may go backward and
forward).
2. Efficient Node Deletion:
o With a pointer to the previous node, deleting a node is faster and doesn’t require
traversing from the head.
oFor example, if we want to delete the last node, we can reach it directly from the
previous node, while in a singly linked list, we would need to traverse from the
beginning.
3. Improved Insertion and Deletion at Both Ends:
o A doubly linked list allows direct insertion and deletion at both the beginning and
end without needing to traverse the list.
o
For instance, inserting at the end in a singly linked list requires traversal unless a
tail pointer is maintained. In doubly linked lists, insertion and deletion from the
end are O(1) operations.
4. Complexity Comparison:
o Doubly linked lists are slightly more complex to implement due to the extra
pointer but provide flexibility in navigation and operations.
Example Code for Deleting a Node in Doubly Linked List: The function delete(p, &x) deletes
the node pointed by p and updates x with the deleted data.
x = p->data;
if (p->prev) p->prev->next = p-
>next; else head = p->next; if (p-
>next) p->next->prev = p->prev;
delete p;
}
• Parameters:
o p : Node to be deleted. o head : Reference to the head node for
updating if the head node is deleted. o x : Variable to store the data of the
deleted node for further use if required.
1. Continuous Traversal:
o In a circular linked list, the last node points back to the first node. This creates a
loop, allowing continuous traversal of the list.
o
oThis property is particularly useful in applications that require circular or
repetitive access, such as round-robin scheduling in operating systems.
2. Efficient Navigation:
A circular linked list allows for a more efficient setup for applications that cycle
through data continuously. For example, in multiplayer gaming where players
take turns in a loop, a circular list lets us return to the start without additional
checks.
3. No NULL Pointers for End Node:
o Since the last node in a circular linked list points back to the head node instead
of NULL, it avoids issues with null pointers when implementing circular
behavior, reducing the need for extra conditions or checks.
Doubly Linked List Advantages:
1. Bidirectional Traversal:
o In a doubly linked list, each node has both a next and prev pointer, enabling
traversal in both forward and backward directions. o This feature is useful in
applications like browser history navigation, where users may want to go backward
and forward easily.
2. Efficient Deletion of Nodes:
o In a doubly linked list, any node can be deleted without traversing from the head.
Once a node is located, it can be removed directly since it has a prev pointer. o For
instance, deleting the last node in a singly linked list requires traversal from the head,
while in a doubly linked list, it can be done in constant time if we keep a pointer to
the tail node.
3. More Flexible Operations:
o A doubly linked list simplifies certain operations that are challenging in singly
linked lists, like adding or removing elements from both ends. This makes it useful
in data structures that require double-ended functionality, such as deques (double-
ended queues).
2. Algorithms for Operations on Circular Singly Linked List Using Header Node
A circular singly linked list with a header node means the list starts with a dummy or header
node. The header node doesn’t store data but acts as a placeholder, pointing to the start of the
actual data nodes.
1. Initialize New Node: o Create a new node, newNode , with the desired data and set its
next pointer to NULL .
o
2. Check if List is Empty:
o If the header node's next pointer is NULL (indicating an empty list), point the
header’s next to the newNode .
o Also, set newNode->next to the header node, completing the circular link.
3. Traverse to the Last Node:
If the list is not empty, start from the header node and traverse to the last node
(where current->next points back to the header).
4. Insert New Node:
o Set the last node’s next pointer to newNode .
o Set newNode->next to the header node, maintaining the circular structure.
5. End of Algorithm.
Algorithm in Pseudocode:
If header.next is NULL:
// List is empty
header.next = newNode
newNode.next = header // Link back to header
Else:
current = header.next While
current.next != header:
current = current.next
End While
current.next =
newNode
newNode.next = header // Maintain circular link
End If
End Function
1. Initialize New Node: o Create a new node, newNode , with the desired data.
2. Check if List is Empty:
o If the list is empty (header’s next pointer is NULL), point header->next to newNode
and newNode->next to the header, creating a self-loop.
3. Set New Node’s next :
o If the list is not empty, set newNode->next to point to the node currently following
the header ( header->next ).
o
4. Update Header Node’s Next Pointer: o Point header->next to the newNode , making it
the first node in the list.
5. Traverse to Last Node:
o If the list was not empty, traverse to the last node (where current->next points to the
header).
6. Maintain Circular Link: o Set the last node’s next pointer to newNode to maintain the
circular structure.
7. End of Algorithm.
Algorithm in Pseudocode:
If header.next is NULL:
// List is empty
header.next = newNode
newNode.next = header // Link back to header
Else:
newNode.next = header.next // Point new node to first node
header.next = newNode // Set header's next to new node
// Traverse to last node
current = newNode.next
While current.next != header:
current = current.next
End While
current.next = newNode // Maintain circular link
End If
End Function
ASSIGNEMENT- 4
Tree Datastructure:
1. Discuss following with reference to trees. Tree Ans.
A tree is a hierarchical data structure consisting of nodes connected by
edges. It is acyclic (no cycles) and connected, with a single root node from
which all other nodes descend. Key terms in tree structures include:
• Root: The topmost node.
• Node: An individual element in the tree, which holds data and may have
child nodes.
• Child: A node directly connected to another node (its parent).
• Leaf: A node with no children.
• Parent: A node that has one or more child nodes.
• Subtree: A tree formed by any node and all its descendants.
• Depth: The number of edges from the root to a node.
• Height: The number of edges from a node to its farthest leaf. Types of
Trees:
1. Binary Tree: Each node has at most two children.
2. Binary Search Tree (BST): A binary tree where left child < node < right
child.
3. AVL Tree: A self-balancing binary search tree.
3. Construct a tree for the given inorder and postorder traversals Inorder
DGBAHEICF Postorder GDBHIEFCA
Ans. To construct a tree from inorder and postorder traversals, follow these
steps:
1. Identify the root: The last element of the postorder sequence is always the
root. For this problem, the root is A (last in postorder).
2. Split inorder sequence: Use the root to divide the inorder sequence into the
left and right subtrees: o Left subtree (elements before the root in inorder):
DGBo
Right subtree (elements after the root in inorder): H E I C F
3. Split postorder sequence: Exclude the root, and the remaining postorder
sequence will be divided between the left and right subtrees: o Left subtree
(postorder for left subtree): G D B o Right subtree
(postorder for right subtree): H I E F C 4. Recursively
construct subtrees:
For the left subtree, the root is B (from postorder), with left
o
child E (which has children H and I) and right child F. Final Tree:
A
/ \
B C
/\ /\
G D E F
/\
H I
This is the tree constructed from the given inorder and postorder traversals.
4. Give the preorder and Inorder traversal of the tree given in below fig.
Ans.
To find the preorder and inorder traversal of this binary tree, let's analyze the
structure based on the image. Tree Structure
The tree appears as follows:
F
/ \
B G
/\ \
A D I
/\ /
C E H
Traversal Definitions
• Preorder Traversal (Root, Left, Right): Visit the root node first, then
recursively visit the left subtree, followed by the right subtree.
• Inorder Traversal (Left, Root, Right): Recursively visit the left subtree
first, then visit the root node, followed by the right subtree. Preorder
Traversal
1. Start at F
2. Move to B
3. Move to A
4. Move to D
5. Move to C
6. Move to E
7. Move to G
8. Move to I
9. Move to H
Preorder Traversal: F, B, A, D, C, E, G, I, H
Inorder Traversal
1. Start at the leftmost node A
2. Move up to B
3. Move to C
4. Move up to D
5. Move to E
6. Move up to F
7. Move to G
8. Move to H
9. Move up to I
Inorder Traversal: A, B, C, D, E, F, G, H, I
Final Answer
• Preorder Traversal: F, B, A, D, C, E, G, I, H
• Inorder Traversal: A, B, C, D, E, F, G, H, I
5. Construct binary search tree for the following data Find its
inorder, preorder and postorder traversal
1. 10,3,15,22,6,45,65,23,78,34,5.
➔ 10
/\
3 15
\ \
6 22
/ \
5 45
/\
23 65
\ \
34 78
2.50, 60, 25, 40, 30, 70, 35, 10, 55, 65, 5
➔ 50
/\
25 60
/\ /\
10 40 55 70
/ / /
5 30 65
\
35
➔ 45
/ \
39 56
/ / \
12 54 78
/ \ / \
10 34 67 89
5. 60, 15, 4, 30, 70, 65, 10, 95, 25, 34 Find its inorder, preorder and
postorder traversal
➔ Inorder Traversal : 4, 10, 15, 25, 30, 34, 60, 65, 70, 95
Preorder Traversal : 60, 15, 4, 10, 30, 25, 34, 70, 65, 95 Postorder
Traversal: 10, 4, 25, 34, 30, 15, 65, 95, 70, 60
7. First insert 10 and then insert 24. After these insertions, delete 37 and then
delete 22 from the following binary search tree. Draw the tree after each
operation.
Step 1: Insert 10
• Inserted 10 as the right child of 9. Tree
after Inserting 10
14
/ \
9 26
/\ /
7 10 22 37
\ \
17 40
\
20
Step 2: Insert 24 •
Inserted 24 as the right child of 22.
14
/ \
9 26
/\ / \
7 10 22 37
\ \
17 40
\
20
\
24
Step 3: Delete 37
• Replaced 37 with its only child, 40.
14
/ \
9 26
/\ / \
7 10 22 40
\
17
\
20
\
24
Step 4: Delete 22 • Replaced 22 with its in-order successor, 24, and removed
the original 24.
14
/ \
9 26
/\ / \
7 10 24 40
\
17
\
20
Graph:
1.Consider the graph shown in below figure. Find depth-first and breadth
first traversals of this graph starting at A
Ans. To find the depth-first and breadth-first traversals of the graph starting at
node A, let's examine the graph structure in the image:
The graph structure based on the image seems to be:
• A is connected to B, C, and D.
• C is connected to E and F.
Given this structure, we can determine the traversals as follows:
Depth-First Traversal (DFS) Starting from A
In DFS, we explore as far as possible along each branch before backtracking.
1. Start at A.
2. Move to B.
3. Backtrack to A and move to C.
4. From C, move to E.
5. Backtrack to C and move to F.
6. Backtrack to C, then back to A, and finally move to D.
DFS Traversal: A→B→C→E→F→D
Breadth-First Traversal (BFS) Starting from A
In BFS, we explore all neighbors at the present depth before moving on to nodes
at the next depth level.
1. Start at A.
2. Visit A's neighbors: B, C, and D.
3. Move to C's neighbors (since B and D have no other connections): E and F.
BFS Traversal: A→B→C→D→E→F
These are the DFS and BFS traversals starting from node A.
2. Define spanning tree and minimum spanning tree. Find the minimum
spanning tree of the graph shown in figure.
Ans. Spanning Tree: A spanning tree of a graph is a subgraph that includes all
the vertices of the original graph and is a tree (i.e., it has no cycles). It connects
all the vertices with the minimum number of edges needed to keep the graph
connected.8+5`
Minimum Spanning Tree (MST): A minimum spanning tree is a spanning tree
with the smallest possible total edge weight. It is a subgraph that connects all
vertices in the graph with the minimum sum of edge weights, ensuring no cycles.
MST of the Graph
Using Kruskal’s Algorithm:
• Edges in MST: C−D (1), B−C (2), A−B (4), A−E (5)
• Total Weight: 1+2+4+5=12
MST Weight: 12
3. Explain the breadth first search and depth first search tree traversal on the
following graph.
c
Ans. BFS Traversal: A → B → C → D → E → F → G DFS
Traversal: A → B → D → E → C → F → G
➔ D→E→A
3. Is the above graph a multigraph? Give a reason for your answer.
➔yes
4. What is the total degree of node A.
➔3
6.Obtain the adjacency matrix A for the following graph. Find A2. Find
outdegree of E and D nodes.
Ans. A B C D E
A 0 1 1 1 0
B 1 0 0 1 1
C 1 0 0 1 0
D 1 1 1 0 1
E 0 1 0 1 0
Outdegree of E node :- 2
Outdegree of D node :- 2