0% found this document useful (0 votes)
5 views13 pages

CAT-1 Assignment (3122247001066)

The document outlines an assignment on data structures and algorithms, focusing on implementing a queuing system for IP requests using a singly linked list and a binary search tree for IP address management. It includes pseudocode and C code implementations for enqueueing, dequeueing, and classifying IP addresses as wired or wireless, static or dynamic. The document also details the expected outputs and correctness of the implementations.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views13 pages

CAT-1 Assignment (3122247001066)

The document outlines an assignment on data structures and algorithms, focusing on implementing a queuing system for IP requests using a singly linked list and a binary search tree for IP address management. It includes pseudocode and C code implementations for enqueueing, dequeueing, and classifying IP addresses as wired or wireless, static or dynamic. The document also details the expected outputs and correctness of the implementations.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

Data Structures and Algorithms

Assignment - 1
Name: K.S.Vijayaraaghavan Reg.no:3122247001062

Question 1: Pre-IP-Assignment Phase


Problem Statement: Construct a queuing system to record the streaming of IP requests from devices.
Devices join the queue (waiting for IP assignment) and leave once their IP is assigned. New devices can join
and leave at any time.

Approach

• Use a singly linked list to implement a FIFO queue.


• Each node stores a device’s MAC address.
• Enqueue (join): insert at rear in O(1).
• Dequeue (leave): remove from front in O(1).
• Maintain front, rear, and count in a DeviceQueue struct.

Pseudocode
// Initialize empty queue
function createQueue():
queue.front ← null
queue.rear ← null
queue.count ← 0
return queue

// Check if queue empty


function isEmpty(queue):
return (queue.count == 0)

// Enqueue device with MAC


function enqueue(queue, mac):
node ← new Device(mac)
if isEmpty(queue):
queue.front ← node
queue.rear ← node
else:
queue.rear.next ← node
queue.rear ← node
queue.count ← queue.count + 1

// Dequeue device (assign IP)


function dequeue(queue):
if isEmpty(queue):
return null
node ← queue.front
queue.front ← node.next
queue.count ← queue.count - 1
if isEmpty(queue):
queue.rear ← null
node.next ← null
return node

// Display current queue


function displayQueue(queue):
print "Devices in Queue (total = ", queue.count, "):"
current ← queue.front
position ← 1
while current ≠ null:
print position, ". MAC: ", current.mac
current ← current.next
position ← position + 1

// Free all nodes


function freeQueue(queue):
while not isEmpty(queue):
node ← dequeue(queue)
delete node
delete queue

Code Implementation

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

// Node for each device


typedef struct Device {
char mac[18]; // "XX:XX:XX:XX:XX:XX"
struct Device *next;
} Device;

// Queue structure
typedef struct {
Device *front;
Device *rear;
int count;
} DeviceQueue;

// Create an empty queue


DeviceQueue* createQueue() {
DeviceQueue *q = malloc(sizeof(DeviceQueue));
q->front = q->rear = NULL;
q->count = 0;
return q;
}

bool isEmpty(DeviceQueue *q) {


return (q->count == 0);
}

// Create a new device node


Device* createDevice(const char *mac) {
Device *d = malloc(sizeof(Device));
strcpy(d->mac, mac);
d->next = NULL;
return d;
}

// Enqueue: join the queue


void enqueue(DeviceQueue *q, const char *mac) {
Device *d = createDevice(mac);
if (isEmpty(q)) {
q->front = q->rear = d;
} else {
q->rear->next = d;
q->rear = d;
}
q->count++;
}

// Dequeue: leave the queue (assign IP)


Device* dequeue(DeviceQueue *q) {
if (isEmpty(q)) return NULL;
Device *d = q->front;
q->front = d->next;
q->count--;
if (isEmpty(q)) q->rear = NULL;
d->next = NULL;
return d;
}

// Display all waiting devices


void displayQueue(DeviceQueue *q) {
printf("\nDevices in Queue (total=%d):\n", q->count);
if (isEmpty(q)) {
printf("<empty>\n");
return;
}
Device *cur = q->front;
int pos = 1;
while (cur) {
printf("%d. MAC: %s\n", pos++, cur->mac);
cur = cur->next;
}
}

// Free all memory


void freeQueue(DeviceQueue *q) {
while (!isEmpty(q)) {
Device *d = dequeue(q);
free(d);
}
free(q);
}

int main() {
DeviceQueue *q = createQueue();
printf("Adding devices...\n");
enqueue(q, "00:1A:2B:3C:4D:5E");
enqueue(q, "11:22:33:44:55:66");
enqueue(q, "AA:BB:CC:DD:EE:FF");
displayQueue(q);

printf("\nAssigning IP to next device...\n");


Device *d = dequeue(q);
if (d) {
printf("Assigned IP to MAC: %s\n", d->mac);
free(d);
}
displayQueue(q);

freeQueue(q);
return 0;
}

What happens in the code:

• Three devices with MAC addresses are added to a queue.


• The queue is displayed showing all three devices in the order they arrived (FIFO).
• Then, one device is dequeued (the one at the front).
• The queue is displayed again with the remaining two devices.

Output

PS C:\Desktop\Folders\College\SEM-2\DSA\ass1> gcc q1.c -o file

PS C:\Desktop\Folders\College\SEM-2\DSA\ass1> ./file

Adding devices...

Devices in Queue (total=3):

1. MAC: 00:1A:2B:3C:4D:5E

2. MAC: 11:22:33:44:55:66

3. MAC: AA:BB:CC:DD:EE:FF

Assigning IP to next device...

Assigned IP to MAC: 00:1A:2B:3C:4D:5E

Devices in Queue (total=2):

1. MAC: 11:22:33:44:55:66

2. MAC: AA:BB:CC:DD:EE:FF

Why this is correct:

• Devices are handled in FIFO order.


• The MAC address at the front gets an IP assigned and is removed.
• Queue state updates as expected.
Question 2: IP-Assignment Phase
Problem Statement: Record dynamically-assigned (DIP) and static IP (SIP) addresses. Addresses in 10.0.1.*
are wired; 10.0.2.* are wireless. If last octet < 100 → SIP; otherwise DIP. Support both wired/wireless and
SIP/DIP categories.

Approach

• Use a Binary Search Tree (BST) keyed by full IP string for efficient insertion and lookup.
• Each node stores:
o address (string)
o isWired (bool)
o isStatic (bool)
o left/right child pointers
• Insertion or search is O(h). In-order traversal groups by category.

Pseudocode
function classifyIP(ipStr):
prefix, last ← split ipStr at last dot
isWired ← (prefix == "10.0.1")
lastOctet ← toInteger(last)
isStatic ← (lastOctet < 100)
return (isWired, isStatic)

function insertNode(root, ipStr):


if root is null:
node ← new BSTNode(ipStr, classifyIP(ipStr))
return node
if ipStr < root.ipStr:
root.left = insertNode(root.left, ipStr)
else if ipStr > root.ipStr:
root.right = insertNode(root.right, ipStr)
return root

function displayByType(root, wantWired, wantStatic):


if root is null: return
displayByType(root.left, wantWired, wantStatic)
if root.isWired == wantWired and root.isStatic == wantStatic:
print root.address, "(", wiredOrWireless, ", ", staticOrDynamic, ")"
displayByType(root.right, wantWired, wantStatic)

Code Implementation

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#define WIRED_PREF "10.0.1"


#define WIRELESS_PREF "10.0.2"
#define SIP_LIMIT 100

// BST node for IP


typedef struct IPNode {
char address[16];
bool isWired;
bool isStatic;
struct IPNode *left, *right;
} IPNode;

// Create and classify


IPNode* createNode(const char *ip) {
IPNode *n = malloc(sizeof(IPNode));
strcpy(n->address, ip);
n->isWired = (strncmp(ip, WIRED_PREF, strlen(WIRED_PREF)) == 0);
int last = atoi(strrchr(ip, '.') + 1);
n->isStatic = (last < SIP_LIMIT);
n->left = n->right = NULL;
return n;
}

// BST insert
IPNode* insertIP(IPNode *root, const char *ip) {
if (!root) return createNode(ip);
int cmp = strcmp(ip, root->address);
if (cmp < 0) root->left = insertIP(root->left, ip);
else if (cmp > 0) root->right = insertIP(root->right, ip);
return root;
}

// In-order display by category


void displayByType(IPNode *root, bool wantWired, bool wantStatic) {
if (!root) return;
displayByType(root->left, wantWired, wantStatic);
if (root->isWired == wantWired && root->isStatic == wantStatic) {
printf("%s (%s, %s)\n",
root->address,
root->isWired ? "Wired" : "Wireless",
root->isStatic ? "Static" : "Dynamic");
}
displayByType(root->right, wantWired, wantStatic);
}

// Free BST
void freeTree(IPNode *root) {
if (!root) return;
freeTree(root->left);
freeTree(root->right);
free(root);
}

int main() {
IPNode *root = NULL;
// Sample inserts
root = insertIP(root, "10.0.1.50");
root = insertIP(root, "10.0.1.150");
root = insertIP(root, "10.0.2.75");
root = insertIP(root, "10.0.2.200");

printf("\nWired Static IPs:\n");


displayByType(root, true, true);
printf("\nWired Dynamic IPs:\n");
displayByType(root, true, false);
printf("\nWireless Static IPs:\n");
displayByType(root, false, true);
printf("\nWireless Dynamic IPs:\n");
displayByType(root, false, false);

freeTree(root);
return 0;
}

What happens in the code:

• Four IP addresses are inserted into a BST.


• Each IP is classified based on:
o Prefix: 10.0.1 for wired, 10.0.2 for wireless.
o Last octet: < 100 means static (SIP), otherwise dynamic (DIP).
• IPs are then displayed by category.

Output

PS C:\Desktop\Folders\College\SEM-2\DSA\ass1> gcc q2.c -o file

PS C:\Desktop\Folders\College\SEM-2\DSA\ass1> ./file

Wired Static IPs:

10.0.1.50 (Wired, Static)

Wired Dynamic IPs:

10.0.1.150 (Wired, Dynamic)

Wireless Static IPs:

10.0.2.75 (Wireless, Static)

Wireless Dynamic IPs:

10.0.2.200 (Wireless, Dynamic)

Why this is correct:

• All IPs are categorized based on the rules.


• The display shows exactly one IP per category, matching the insertion.
Question 3: Adapted Data Structure for Add/Delete/Search
Problem Statement: Adapt the BST from Q2 to efficiently support insertion, deletion, and search of IP
addresses by category.

Approach

• Extend the BST with functions:


o searchIP(root, ipStr) → returns node or NULL.
o deleteIP(root, ipStr) → removes node, restructures tree.
• Use in-order successor for deleting nodes with two children.

Pseudocode
function searchIP(root, ipStr):
if root is null or root.address == ipStr:
return root
if ipStr < root.address:
return searchIP(root.left, ipStr)
else:
return searchIP(root.right, ipStr)

function deleteIP(root, ipStr):


if root is null: return null
if ipStr < root.address:
root.left = deleteIP(root.left, ipStr)
else if ipStr > root.address:
root.right = deleteIP(root.right, ipStr)
else:
// found node to delete
if root.left is null:
return root.right
else if root.right is null:
return root.left
// two children: find successor
succ = minValue(root.right)
root.address, root.isWired, root.isStatic ← succ’s values
root.right = deleteIP(root.right, succ.address)
return root

function minValue(node):
while node.left ≠ null:
node = node.left
return node

Code Implementation

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#define WIRED_PREFIX "10.0.1"


#define WIRELESS_PREFIX "10.0.2"
#define SIP_THRESHOLD 100

typedef struct IPNode {


char address[16];
bool isWired;
bool isStatic;
struct IPNode *left, *right;
} IPNode;

// Function to classify and create IP node


IPNode* createNode(const char *ip) {
IPNode *node = (IPNode *)malloc(sizeof(IPNode));
strcpy(node->address, ip);
node->isWired = (strncmp(ip, WIRED_PREFIX, strlen(WIRED_PREFIX)) == 0);
int lastOctet = atoi(strrchr(ip, '.') + 1);
node->isStatic = (lastOctet < SIP_THRESHOLD);
node->left = node->right = NULL;
return node;
}

// Insert IP
IPNode* insertIP(IPNode *root, const char *ip) {
if (!root) return createNode(ip);
int cmp = strcmp(ip, root->address);
if (cmp < 0) root->left = insertIP(root->left, ip);
else if (cmp > 0) root->right = insertIP(root->right, ip);
return root;
}

// Display IPs by category


void displayIPsByType(IPNode *root, bool isWired, bool isStatic) {
if (!root) return;
displayIPsByType(root->left, isWired, isStatic);
if (root->isWired == isWired && root->isStatic == isStatic) {
printf("%s (%s, %s)\n",
root->address,
root->isWired ? "Wired" : "Wireless",
root->isStatic ? "Static" : "Dynamic");
}
displayIPsByType(root->right, isWired, isStatic);
}

// Search IP
IPNode* searchIP(IPNode *root, const char *ip) {
if (!root || strcmp(root->address, ip) == 0) return root;
if (strcmp(ip, root->address) < 0) return searchIP(root->left, ip);
return searchIP(root->right, ip);
}

// Find minimum value node


IPNode* minValueNode(IPNode *node) {
IPNode *current = node;
while (current && current->left) current = current->left;
return current;
}

// Delete IP
IPNode* deleteIP(IPNode *root, const char *ip) {
if (!root) return NULL;
int cmp = strcmp(ip, root->address);
if (cmp < 0) root->left = deleteIP(root->left, ip);
else if (cmp > 0) root->right = deleteIP(root->right, ip);
else {
if (!root->left) {
IPNode *temp = root->right;
free(root);
return temp;
} else if (!root->right) {
IPNode *temp = root->left;
free(root);
return temp;
}
IPNode *temp = minValueNode(root->right);
strcpy(root->address, temp->address);
root->isWired = temp->isWired;
root->isStatic = temp->isStatic;
root->right = deleteIP(root->right, temp->address);
}
return root;
}

// Free the BST


void freeIPTree(IPNode *root) {
if (!root) return;
freeIPTree(root->left);
freeIPTree(root->right);
free(root);
}

int main() {
IPNode *root = NULL;

// Insert IPs
root = insertIP(root, "10.0.1.50"); // Wired SIP
root = insertIP(root, "10.0.1.150"); // Wired DIP
root = insertIP(root, "10.0.2.75"); // Wireless SIP
root = insertIP(root, "10.0.2.200"); // Wireless DIP

// Display
printf("Wired Static IPs:\n");
displayIPsByType(root, true, true);

printf("\nWired Dynamic IPs:\n");


displayIPsByType(root, true, false);

printf("\nWireless Static IPs:\n");


displayIPsByType(root, false, true);

printf("\nWireless Dynamic IPs:\n");


displayIPsByType(root, false, false);

// Search
const char *targetIP = "10.0.1.50";
IPNode *found = searchIP(root, targetIP);
if (found) {
printf("\nFound IP: %s (%s, %s)\n", found->address,
found->isWired ? "Wired" : "Wireless",
found->isStatic ? "Static" : "Dynamic");
} else {
printf("\nIP not found.\n");
}

// Delete
printf("\nDeleting IP: %s\n", targetIP);
root = deleteIP(root, targetIP);

// Display after deletion


printf("\nUpdated Wired Static IPs:\n");
displayIPsByType(root, true, true);

// Clean up
freeIPTree(root);
return 0;
}

What happens in the code:

• Same four IPs are inserted as in Question 2.


• An IP (10.0.1.50) is searched for and found.
• Then, that same IP is deleted.
• The updated list of "Wired Static IPs" is shown again.

Output

Wired Static IPs:

10.0.1.50 (Wired, Static)

Wired Dynamic IPs:

10.0.1.150 (Wired, Dynamic)

Wireless Static IPs:

10.0.2.75 (Wireless, Static)

Wireless Dynamic IPs:

10.0.2.200 (Wireless, Dynamic)


Found IP: 10.0.1.50 (Wired, Static)

Deleting IP: 10.0.1.50

Updated Wired Static IPs: //(empty)

Why this is correct:

• The search finds the target IP in the BST.


• Deletion removes that IP.
• The updated display confirms it's no longer in the BST.

Question 4: Time Complexity Analysis


1. Add device to queue

Time Complexity: O(1) (Constant Time)

Why?

• When a new device joins the queue (enqueue), it is added at the rear.
• We simply update the rear pointer and link the new node.
• No traversal or shifting is required, regardless of queue size.

2. Remove device from queue

Time Complexity: O(1) (Constant Time)

Why?

• Removing a device (dequeue) happens at the front of the queue.


• We just update the front pointer to the next node.
• Again, no need to traverse the queue, so it’s a constant-time operation.

3. Add IP to BST

Time Complexity:

• Best case: O(log n) (Balanced BST)


• Worst case: O(n) (Skewed BST)

Why?

• To insert an IP into a binary search tree (BST), the program compares values from the root down to a
leaf.
• In a balanced BST, this takes about log₂(n) steps.
• If the tree is unbalanced (e.g., every node only has one child), the path may be n nodes long.

4. Search IP in BST

Time Complexity:

• Best case: O(log n)


• Worst case: O(n)

Why?

• Searching is similar to insertion.


• You compare the target IP to the current node, and move left or right accordingly.
• In a balanced tree, the number of comparisons is minimized.
• In a skewed tree, you might have to check all nodes, making it linear time.

5. Delete IP from BST

Time Complexity:

• Best case: O(log n)


• Worst case: O(n)

Why?

• First, the program must find the IP to delete (same as search → O(h)).
• Then:
o If the node has no children or one child: deletion is straightforward.
o If it has two children: you must also find the in-order successor (minimum in right subtree),
which can take O(h) time.
• So the total cost is based on the height h of the tree.

Summary Table

Operation Time Complexity Explanation


Enqueue (Add to queue) O(1) Add at rear, constant-time pointer update
Dequeue (Remove from queue) O(1) Remove from front, no traversal needed
Insert IP (BST) O(log n) to O(n) Depends on tree height (balanced or skewed)
Search IP (BST) O(log n) to O(n) Same as above
Delete IP (BST) O(log n) to O(n) Search + possible restructure (successor logic)

You might also like