Assignment No 3
Assignment No 3
Arrays and Linked Lists are fundamental data structures in computer science, and they differ in
their structure, memory management, efficiency, and operations.
1. Structure:
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: Insertion and deletion are costly operations (O(n) in the worst case) because all
elements following the inserted/deleted element must be shifted to maintain contiguous
memory.
Linked List: Inserting and deleting nodes in a linked list, especially at the beginning or
middle, is more efficient, as only the pointers need to be updated. However, accessing a
specific element by position requires traversing from the head, which is O(n).
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).
Linked List: Used in scenarios requiring frequent insertions and deletions (e.g.,
implementation of stacks, queues, and real-time applications).
.
An ascending priority queue is a data structure where elements are ordered based on priority,
with the lowest priority (smallest value) at the front. In this example, we will use a singly linked
list to implement this priority queue.
Algorithm:
1. Insertion (insert()):
o Step 1: Create a new node with the given priority and data.
o Step 2: If the list is empty or if the priority of the new node is less than the head
node, set the new node as the head.
o Step 3: Otherwise, traverse the list to find the correct position based on priority
order. Insert the new node at the appropriate position to maintain ascending order.
o Complexity: O(n) due to the traversal to find the insertion point.
2. Removal (remove()):
o Step 1: Check if the list is empty. If it is, output an error message.
o Step 2: Remove the head node, as it contains the element with the lowest priority.
o Step 3: Update the head pointer to the next node.
o Complexity: O(1) as it only removes the head.
Code Example in C:
c
Copy code
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
int priority;
struct Node* next;
};
Reversing a singly linked list involves changing the direction of the next pointers, such that the
last node becomes the head and the head node becomes the last node.
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:
void reverse(struct Node** head) {
struct Node* prev = NULL;
struct Node* current = *head;
struct Node* next = NULL;
This question requires two functions: one for inserting a node after a specified node and another
for deleting the node after a specified node.
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:
Code Example in C:
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:
Detailed Explanation:
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;
};
Brief Explanation:
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:
Code Example:
temp->next = head2;
head2->prev = temp;
}
Brief 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.
o For 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;
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. Advantages of Circular and Doubly Linked Lists over Singly Linked Lists
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 This property is particularly useful in applications that require circular or
repetitive access, such as round-robin scheduling in operating systems.
2. Efficient Navigation:
o 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.
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.
Algorithm in Pseudocode:
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
These algorithms are designed to handle circular singly linked lists using a header node, making
insertions flexible and efficient. The header node enables consistent management of the list's
start and helps avoid special cases when the list is empty or only has one node.