Important question
Question 1: Describe the three types of structures used for storing strings, mentioning one advantage and one disadvantage of each.Âļ
Question 1: Describe the three types of structures used for storing strings, mentioning one advantage and one disadvantage of each.
In string processing, strings are sequences of characters. Based on memory allocation strategies (āĻŽā§āĻŽā§āϰāĻŋ āĻŦāĻŖā§āĻāύ āĻā§āĻļāϞ) and structural organization, three primary structures are used to store strings:
1. Fixed-Length Array Structure (āϏā§āĻĨāĻŋāϰ āĻĻā§āϰā§āĻā§āϝā§āϰ āĻ ā§āϝāĻžāϰ⧠āĻāĻžāĻ āĻžāĻŽā§ / Record Structure)Âļ
- Description: Memory is allocated as a static, fixed-size contiguous block (āĻĒāϰāϏā§āĻĒāϰ āϏāĻāϞāĻā§āύ āĻŽā§āĻŽā§āϰāĻŋ āĻŦā§āϞāĻ) capable of holding a predetermined maximum number of characters (\(N\)). If the actual string length is less than \(N\), the remaining slots are filled with padding characters (āϝā§āĻŽāύ: āĻĢāĻžāĻāĻāĻž āϏā§āĻĨāĻžāύ āĻŦāĻž Null Character).
- Advantage: Direct and rapid \(O(1)\) random access (āϝāĻĨā§āĻā§āĻ āĻŽā§āĻŽā§āϰāĻŋ āĻ ā§āϝāĻžāĻā§āϏā§āϏ) to any character via array indexing, along with simple memory management (āϏāĻšāĻ āĻŽā§āĻŽā§āϰāĻŋ āĻŦā§āϝāĻŦāϏā§āĻĨāĻžāĻĒāύāĻž) as pointer overhead is zero.
- Disadvantage: Inflexible capacity leading to internal fragmentation (āĻ āĻā§āϝāύā§āϤāϰā§āĻŖ āĻŽā§āĻŽā§āϰāĻŋ āĻ āĻĒāĻāϝāĻŧ) when storing short strings, and risk of data truncation (āĻĄā§āĻāĻž āĻā§āĻāĻā§ āϝāĻžāĻā§āĻž) or buffer overflow if the string exceeds the pre-allocated length \(N\).
2. Variable-Length Structure with Fixed Maximum (āĻĒāϰāĻŋāĻŦāϰā§āϤāύāĻļā§āϞ āĻĻā§āϰā§āĻā§āϝ āϏāĻš āϏā§āĻĨāĻŋāϰ āϏāϰā§āĻŦā§āĻā§āĻ āϏā§āĻŽāĻž)Âļ
- Description: Memory is allocated up to a fixed maximum bound (\(N_{\max}\)), but the actual current length (\(L \le N_{\max}\)) is dynamically tracked using either an explicit length header (āĻĻā§āϰā§āĻā§āϝ āύāĻŋāϰā§āĻĻā§āĻļāĻ āĻšā§āĻĄāĻžāϰ) at the start of the memory block or a sentinel marker (āϝā§āĻŽāύ: Null Character
\0). - Advantage: Eliminates the need for blank padding, allowing precise processing up to the actual string boundary while preventing character truncation up to \(N_{\max}\).
- Disadvantage: Memory allocation remains bounded by \(N_{\max}\), leading to wasted reserved memory (āĻ āύāĻŦā§āϝāĻŦāĻšā§āϤ āϏāĻāϰāĻā§āώāĻŋāϤ āϏā§āĻĨāĻžāύ) if the assigned maximum bound is significantly larger than typical string sizes.
3. Linked Storage Structure (āϞāĻŋāĻā§āĻāĻĄ āϏā§āĻā§āϰā§āĻ āĻāĻžāĻ āĻžāĻŽā§ / Pointer-based Representation)Âļ
- Description: Strings are stored across a collection of dynamically allocated nodes (āĻāϤāĻŋāĻļā§āϞāĻāĻžāĻŦā§ āĻŦāϰāĻžāĻĻā§āĻĻāĻā§āϤ āύā§āĻĄ), where each node contains one or a small block of characters along with a pointer (āĻĒā§ā§āύā§āĻāĻžāϰ / āϏāĻāϝā§āĻ āύāĻŋāϰā§āĻĻā§āĻļāĻ) to the next node in sequence.
- Advantage: Completely dynamic memory allocation (āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻāϤāĻŋāĻļā§āϞ āĻŽā§āĻŽā§āϰāĻŋ āĻŦāĻŖā§āĻāύ); strings can grow or shrink indefinitely without fixed bounds, and insertion or deletion operations require only pointer manipulation rather than shifting contiguous elements.
- Disadvantage: High memory overhead (āĻ āϤāĻŋāϰāĻŋāĻā§āϤ āĻŽā§āĻŽā§āϰāĻŋ āĻāϰāĻ) due to pointer fields stored alongside character data, along with poor spatial locality of reference (āϏā§āĻĨāĻžāύāĻŋāĻ āĻŽā§āĻŽā§āϰāĻŋ āϏā§āĻĨāĻžāύā§ā§āϤāĻž) which degrades CPU cache efficiency.
1. Fixed-Length Array Structure
In this approach, memory is statically allocated for a fixed character count. Unused positions are explicitly padded (often with whitespace or zero bytes), and the string cannot exceed the allocated array boundary.
#define FIXED_SIZE 10
// Fixed-length record: 10 bytes allocated, padded with blank spaces
char fixed_str[FIXED_SIZE] = "Data ";
// Accessing character at index 2 (O(1) random access)
char c = fixed_str[2]; // 't'
2. Variable-Length Structure with Fixed Maximum
This structure allocates a fixed maximum buffer, but tracks the actual string length either via a sentinel character (standard C null-terminator \0) or an explicit length prefix.
#define MAX_SIZE 100
// Method A: Standard Null-Terminated String
char str_sentinel[MAX_SIZE] = "Hello"; // Current length = 5, tracks end via '\0'
// Method B: Explicit Length-Prefixed Record (Length Header)
struct VarStringFixedMax {
int length; // Stores current logical length (e.g., 5)
char data[MAX_SIZE]; // Fixed maximum capacity of 100 characters
};
struct VarStringFixedMax str_header = {5, "Hello"};
3. Linked Storage Structure
Characters are stored in dynamically allocated nodes on the heap connected via pointers. This allows indefinite growth at runtime at the expense of pointer overhead.
#include <stdlib.h>
// Singly Linked List: One character per node
struct CharNode {
char data;
struct CharNode *next;
};
// Chunked / Blocked Linked List: Reduces pointer overhead by storing small arrays per node
struct BlockNode {
char chunk[4]; // 4-character block per node
struct BlockNode *next; // Pointer to next block
};
// Example node creation
struct CharNode *create_node(char c) {
struct CharNode *node = (struct CharNode *)malloc(sizeof(struct CharNode));
node->data = c;
node->next = NULL;
return node;
}
Question 2: Explain the purpose of the following string operations: LENGTH, SUBSTRING, INDEX, INSERT, DELETE and REPLACE.Âļ
Question 2: Explain the purpose of the following string operations: LENGTH, SUBSTRING, INDEX, INSERT, DELETE and REPLACE.
String processing relies on primitive operations (āĻŽā§āϞāĻŋāĻ āĻ āĻĒāĻžāϰā§āĻāϰ) defined as follows:
1. LENGTH(S)
- Purpose: Determines and returns the cardinality (āĻāĻĒāĻžāĻĻāĻžāύ āϏāĻāĻā§āϝāĻž / āĻŽā§āĻ āĻ āĻā§āώāϰā§āϰ āϏāĻāĻā§āϝāĻž) or total length of string \(S\).
- Formal Definition: Returns \(n = \vert{}S\vert{}\), where \(n \ge 0\).
- C Example:
2. SUBSTRING(S, initial, length)
- Purpose: Extracts a continuous sequence of characters (āĻāĻĒ-āϏā§āĻā§āϰāĻŋāĻ āύāĻŋāώā§āĻāĻžāĻļāύ) from string \(S\), starting at position
initialand spanninglengthcharacters. - Formal Definition: If \(S = s_1 s_2 \dots s_n\), then \(\text{SUBSTRING}(S, i, k) = s_i s_{i+1} \dots s_{i+k-1}\).
- C Example:
char S[] = "Structure";
char sub[5];
// Extract 4 characters starting from index 3 ('u', 'c', 't', 'u')
strncpy(sub, S + 3, 4);
sub[4] = '\0'; // Null-terminate -> "uctu"
3. INDEX(S, pattern)
- Purpose: Searches string \(S\) for the first occurrence of a target
patternand returns its starting index (āϏā§āĻāύāĻž āϏā§āĻĨāĻžāύ / āĻ āĻŦāϏā§āĻĨāĻžāύ āύāĻŋāϰā§āĻĻā§āĻļāĻ). Ifpatterndoes not exist in \(S\), it returns \(0\) (or a sentinel value like \(-1\)). - Formal Definition: Returns \(i\) such that \(\text{SUBSTRING}(S, i, \vert\text{pattern}\vert) = \text{pattern}\), or \(-1\) if no match exists.
- C Example:
char S[] = "DataStructure";
char *ptr = strstr(S, "Struct");
// Calculate 0-based starting index using pointer arithmetic
int index = (ptr != NULL) ? (int)(ptr - S) : -1; // Returns 4
4. INSERT(S, position, sub)
- Purpose: Splices a new string
subinto target string \(S\) at a specified position, shifting (āϏā§āĻĨāĻžāύāĻžāύā§āϤāϰāĻŋāϤ āĻāϰāĻž) existing characters at and afterpositionto the right to make room. - Formal Definition: Transforms \(S[1\dots n]\) into \(S[1\dots i-1] + \text{sub} + S[i\dots n]\).
- C Example:
char S[20] = "HELO"; // Allocate extra buffer for growth
int pos = 3; // Insert at index 3 before 'O'
char sub[] = "L";
// Shift trailing characters "O\0" right by strlen(sub)
memmove(S + pos + strlen(sub), S + pos, strlen(S) - pos + 1);
// Copy substring into vacated slot
memcpy(S + pos, sub, strlen(sub)); // S becomes "HELLO"
5. DELETE(S, position, length)
- Purpose: Removes a contiguous block of
lengthcharacters from \(S\) beginning atposition, shifting remaining trailing characters (āĻ āĻŦāĻļāĻŋāώā§āĻ āĻ āĻā§āώāϰāϏāĻŽā§āĻš) leftward to fill the gap. - Formal Definition: Transforms \(S[1\dots n]\) into \(S[1\dots i-1] + S[i+k\dots n]\).
- C Example:
char S[] = "Data_Base";
int pos = 4, len = 1; // Remove '_' at index 4
// Shift "Base\0" left over the removed character
memmove(S + pos, S + pos + len, strlen(S) - (pos + len) + 1); // S becomes "DataBase"
6. REPLACE(S, pattern, replacement)
- Purpose: Locates target
patterninside string \(S\) and substitutes (āĻĒā§āϰāϤāĻŋāϏā§āĻĨāĻžāĻĒāύ āĻāϰāĻž) its occurrence with a new substringreplacement. - Formal Definition: Equivalent to finding \(i = \text{INDEX}(S, \text{pattern})\), followed by \(\text{DELETE}(S, i, \vert\text{pattern}\vert)\) and \(\text{INSERT}(S, i, \text{replacement})\).
- C Example:
char S[30] = "Hello World";
char *target = strstr(S, "World");
if (target != NULL) {
char buffer[30];
int prefix_len = target - S;
strncpy(buffer, S, prefix_len);
buffer[prefix_len] = '\0';
strcat(buffer, "Gemini");
strcat(buffer, target + strlen("World"));
strcpy(S, buffer); // S becomes "Hello Gemini"
}
Question 3: Difference Between INSERT and REPLACE
| Feature / Metric | INSERT Operation | REPLACE Operation |
|---|---|---|
| Core Mechanism (āĻŽā§āϞ āĻāĻžāϰā§āϝāĻĒā§āϰāĻŖāĻžāϞā§) | Splices new characters into a specific position without destroying existing characters; shifts existing characters right. | Overwrites/destroys existing characters or target patterns with new content. |
| Impact on Length (āĻĻā§āϰā§āĻā§āϝā§āϰ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ) | Always increases string length: \(\text{Len}_{\text{new}} = \text{Len}_{\text{old}} + \vert\text{sub}\vert\). | Length fluctuates depending on size difference: \(\text{Len}_{\text{new}} = \text{Len}_{\text{old}} - \vert\text{pattern}\vert + \vert\text{replacement}\vert\). |
| Data Preservation (āĻĄā§āĻāĻž āϏāĻāϰāĻā§āώāĻŖ) | Fully preserves all original characters in the target string. | Erases/discards specified characters from the target string. |
| Algorithmic Complexity (āĻāĻāĻŋāϞāϤāĻž) | Requires \(O(N)\) memory shift of trailing characters in contiguous arrays. | Involves pattern search (\(O(N \cdot M)\)) followed by deletion and insertion/memory shift. |
| Execution Example | \(\text{INSERT}(\text{"HELO"}, 4, \text{"L"}) \rightarrow \text{"HELLO"}\) | \(\text{REPLACE}(\text{"HELLA"}, \text{"A"}, \text{"O"}) \rightarrow \text{"HELLO"}\) |
C Implementation Comparison:
// INSERT: Expands memory and preserves all original data
char insert_str[20] = "HELO";
memmove(insert_str + 4, insert_str + 3, 2); // Shift "O\0" right
insert_str[3] = 'L'; // Result: "HELLO" (Length increased from 4 to 5)
// REPLACE: Overwrites data without increasing length (when sizes match)
char replace_str[20] = "HELLA";
replace_str[4] = 'O'; // Overwrite 'A' with 'O' -> "HELLO" (Length remains 5)
Question 3: Explain the difference between the INSERT operation and the REPLACE operation on a string.Âļ
| Feature / Metric | INSERT Operation | REPLACE Operation |
|---|---|---|
| Core Mechanism (āĻŽā§āϞ āĻāĻžāϰā§āϝāĻĒā§āϰāĻŖāĻžāϞā§) | Splices new characters into a specific position without destroying (āϧā§āĻŦāĻāϏ āύāĻž āĻāϰā§) existing characters. Existing characters are shifted right. | Overwrites/destroys (āĻŽā§āĻā§ āĻĒā§āϰāϤāĻŋāϏā§āĻĨāĻžāĻĒāύ āĻāϰāĻž) existing characters or target patterns with new content. |
| Impact on Length (āĻĻā§āϰā§āĻā§āϝā§āϰ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ) | Always increases string length by the inserted length: \(\text{Len}_{\text{new}} = \text{Len}_{\text{old}} + \vert{}\text{sub}\vert{}\). | Length changes based on the difference: \(\text{Len}_{\text{new}} = \text{Len}_{\text{old}} - \vert{}\text{pattern}\vert{} + \vert{}\text{replacement}\vert{}\). |
| Data Preservation (āĻĄā§āĻāĻž āϏāĻāϰāĻā§āώāĻŖ) | Fully preserves (āĻĒā§āϰā§āĻŖāĻžāĻā§āĻ āϏāĻāϰāĻā§āώāĻŖ) all original characters of the target string. | Erases/discards specified characters from the target string. |
| Algorithmic Complexity (āĻāĻāĻŋāϞāϤāĻž) | Requires shifting trailing characters rightward: \(O(N)\) memory shift in contiguous arrays. | Involves pattern search followed by deletion and insertion (or in-place memory overwriting). |
| Example (āĻāĻĻāĻžāĻšāϰāĻŖ) | INSERT("HELO", 4, "L") \(\rightarrow\) "HELLO" |
REPLACE("HELLA", "A", "O") \(\rightarrow\) "HELLO" |
Question 4: What is pattern matching? Explain how the first pattern matching algorithm works.Âļ
What is Pattern Matching?Âļ
Pattern Matching (āĻĒā§āϝāĻžāĻāĻžāϰā§āύ āĻŽā§āϝāĻžāĻāĻŋāĻ) is the algorithmic process of determining the presence and starting position of a target string called a Pattern \(P\) of length \(m\), within a larger body of text called Text \(T\) of length \(n\) (where \(m \le n\)).
How the First Pattern Matching Algorithm (Brute-Force / Naive Algorithm) WorksÂļ
How the First Pattern Matching Algorithm (Brute-Force / Naive Algorithm) Works
The first algorithm uses a sliding window approach (āϏā§āϞāĻžāĻāĻĄāĻŋāĻ āĻāĻāύā§āĻĄā§ āĻĒāĻĻā§āϧāϤāĻŋ) to scan the text \(T\) sequentially from left to right:
Initial Setup
Step 1: Alignment at Index 0
Text: A B B B A B A B A A B
Pattern: A B A A
| | |
(â) (â) (â) -> Mismatch at index 2 ('B' != 'A')
- Compare 1st character:
A==A(Match, move to next) - Compare 2nd character:
B==B(Match, move to next) - Compare 3rd character:
B!=A(Mismatch) - Action: Shift pattern 1 position to the right and backtrack pointer.
Step 2: Alignment at Index 1
- Compare 1st character:
B!=A(Mismatch) - Action: Shift pattern 1 position to the right.
Step 3: Alignment at Index 2
- Compare 1st character:
B!=A(Mismatch) - Action: Shift pattern 1 position to the right.
Step 4: Alignment at Index 3
- Compare 1st character:
B!=A(Mismatch) - Action: Shift pattern 1 position to the right.
Step 5: Alignment at Index 4
Text: A B B B A B A B A A B
Pattern: A B A A
| | | |
(â) (â) (â) (â) -> Mismatch at index 7 ('B' != 'A')
- Compare 1st character:
A==A(Match) - Compare 2nd character:
B==B(Match) - Compare 3rd character:
A==A(Match) - Compare 4th character:
B!=A(Mismatch) - Action: Shift pattern 1 position to the right and backtrack pointer.
Step 6: Alignment at Index 5
- Compare 1st character:
B!=A(Mismatch) - Action: Shift pattern 1 position to the right.
Step 7: Alignment at Index 6
- Compare 1st character:
A==A(Match) - Compare 2nd character:
B==B(Match) - Compare 3rd character:
A==A(Match) - Compare 4th character:
A==A(Match)
All characters of the pattern match completely. The search stops, returning starting index 6.Âļ
Question 5: Why is the first pattern matching algorithm called the "slow" algorithm? Compare it briefly with the second pattern matching algorithm.Âļ
Why is the First Algorithm Called "Slow"?Âļ
The Brute-Force algorithm is termed "slow" due to its inefficient computational complexity caused by unnecessary backtracking (āĻ āĻĒā§āϰāϝāĻŧā§āĻāύā§āϝāĻŧ āĻĒā§āϰā§āĻŦāĻžāĻŦāϏā§āĻĨāĻžāϝāĻŧ āĻŦā§āϝāĻžāĻāĻā§āϰā§āϝāĻžāĻāĻŋāĻ) and redundant character comparisons (āĻĒā§āύāϰāĻžāĻŦā§āϤā§āϤāĻŋāĻŽā§āϞāĻ āϤā§āϞāύāĻž).
- Worst-Case Time Complexity: \(O(n \times m)\), where \(n = \vert{}T\vert{}\) and \(m = \vert{}P\vert{}\).
- Reason for Inefficiency: When a mismatch occurs near the end of pattern \(P\), the algorithm discards all matching information already gathered about the text characters. It resets \(K\) to \(K+1\) and re-examines text characters that were already read in previous passes.
- Example: Searching \(P = \text{"AAAB"}\) in \(T = \text{"AAAAAAAAAAAAAB"}\) causes \((n - m + 1) \times m\) comparisons because every attempt matches \(m-1\) characters before failing at the last character.
Comparison: First Algorithm vs. Second Algorithm (KMP / Automaton Approach)Âļ
| Parameter | First Algorithm (Brute-Force) | Second Algorithm (KMP / Automaton) |
|---|---|---|
| Time Complexity (āϏāĻŽāϝāĻŧ āĻāĻāĻŋāϞāϤāĻž) | Worst Case: \(O(n \cdot m)\) (Quadratic / āĻĻā§āĻŦāĻŋāĻāĻžāϤ āϏāĻŽāϝāĻŧ) | Worst Case: \(O(n + m)\) (Linear / āϰā§āĻāĻŋāĻ āϏāĻŽāϝāĻŧ) |
| Text Pointer Movement (āĻā§āĻā§āϏāĻ āĻĒāϝāĻŧā§āύā§āĻāĻžāϰ āϏāĻā§āĻāĻžāϞāύ) | Backtracks (āĻĒāĻŋāĻāύ⧠āĻĢāĻŋāϰ⧠āϝāĻžā§) repeatedly upon mismatch (\(K \rightarrow K+1\)). | Moves strictly forward (āĻāĻāĻŽā§āĻā§ āϏāĻā§āĻāĻžāϞāύ / Monotonic scan) without backtracking \(T\). |
| Use of Prior Information (āĻĒā§āϰā§āĻŦāĻā§āĻāĻžāύ āĻŦā§āϝāĻŦāĻšāĻžāϰ) | Ignores previously matched characters (āĻā§āύ āϤāĻĨā§āϝ āĻŽāύ⧠āϰāĻžāĻā§ āύāĻž). | Reuses character knowledge using precomputed prefix patterns (āĻāĻĒāϏāϰā§āĻ āϏāĻžāϰāĻŖā§ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§). |
| Preprocessing Phase (āĻĒā§āϰā§āĻŦ-āĻĒā§āϰāϏā§āϏāĻŋāĻ āϧāĻžāĻĒ) | None (\(O(1)\) setup time). | Preprocesses pattern \(P\) into a state transition table / function in \(O(m)\) time. |
Question 6: Explain the role of the table and the graph used in the second pattern matching algorithm.Âļ
In the second pattern matching algorithm (such as the Finite State Automaton / Knuth-Morris-Pratt approach), a Graph and a Table work together to eliminate text pointer backtracking completely.
[ Input Text Character ]
â
âŧ
âââââââââââââââââââââââââââââââ
â Pattern Matching Table â âââ [ Look up Current State & Character ]
ââââââââââââââââŦâââââââââââââââ
â Determines Next State
âŧ
âââââââââââââââââââââââââââââââ
â State Transition Graph â âââ [ Shift to Next State without Backtracking ]
âââââââââââââââââââââââââââââââ
1. Role of the Pattern Transition Graph (āĻĒā§āϝāĻžāĻāĻžāϰā§āύ āĻā§āϰāĻžāύāĻāĻŋāĻļāύ āĻā§āϰāĻžāĻĢ / State Diagram)Âļ
- Definition: A Directed Graph (āĻĻāĻŋāĻāĻŦāϰā§āϤ⧠āĻā§āϰāĻžāĻĢ / Deterministic Finite Automaton) where:
- Nodes (āύā§āĻĄ / āϏā§āĻā§āĻāĻ): Represent states, corresponding to the number of consecutive characters successfully matched so far (\(0, 1, 2, \dots, m\)).
-
Directed Edges (āĻĻāĻŋāĻāĻŦāϰā§āϤ⧠āϤāĻŋāϰāĻāĻŋāĻšā§āύ): Represent state transitions triggered by reading specific incoming characters from text \(T\).
-
Role: Visually represents the structural matching logic of the machine. Successful character matches advance the graph to higher states (\(S_{k} \rightarrow S_{k+1}\)), while mismatches follow failure transitions (āĻŦā§āϝāϰā§āĻĨāϤāĻž āĻā§āϰāĻžāύāĻāĻŋāĻļāύ) pointing directly to the longest matching prefix state, bypassing redundant character checks.
2. Role of the Pattern Transition Table (āĻĒā§āϝāĻžāĻāĻžāϰā§āύ āĻā§āϰāĻžāύāĻāĻŋāĻļāύ āĻā§āĻŦāĻŋāϞ / Next-State Matrix)Âļ
- Definition: A tabular representation (āĻŽā§āϝāĻžāĻā§āϰāĻŋāĻā§āϏ āϰā§āĻĒ) of the state transition graph, formally defined as a function \(f(\text{State}, \text{Character}) \rightarrow \text{Next State}\).
- Role:
- Serves as an \(O(1)\) lookup matrix used during text scanning.
- For every current state \(S\) and input character \(c\), the table explicitly dictates the precise destination state without evaluating complex conditional statements at runtime.
- Key Operational Impact: When a mismatch occurs, the table immediately provides the target state \(S_{\text{next}}\) based on the internal prefix structure of pattern \(P\). This allows the algorithm to keep the text pointer moving forward continuously, achieving an optimal \(O(n)\) time complexity.
1. Define linear array. Which operations are normally performed on a linear structure?Âļ
1. Define linear array. Which operations are normally performed on a linear structure?
A linear array is a finite (āϏāϏā§āĻŽ), ordered collection of a fixed number of homogeneous (āϏāĻŽāĻāĻžāϤā§āϝāĻŧ) data elements stored in contiguous (āϏāĻāϞāĻā§āύ / āĻ āĻŦāĻŋāĻā§āĻāĻŋāύā§āύ) memory locations, where each element is indexed by a continuous sequence of integers.
Linear Array in Memory:
Index: [ 0 ] [ 1 ] [ 2 ] [ 3 ] [ 4 ]
Data: | 10 | 25 | 40 | 55 | 70 |
Address: 0x1000 0x1004 0x1008 0x100C 0x1010
Operations Normally Performed on a Linear Structure:Âļ
- Traversal (āĻĒā§āϰāĻĻāĻā§āώāĻŋāĻŖ / āĻĒāϰāĻŋāĻā§āϰāĻŽāĻŖ): Processing (printing, reading, or modifying) every element in the array exactly once from the lower bound to the upper bound.
- Insertion (āϏāύā§āύāĻŋāĻŦā§āĻļ): Adding a new data element at a designated index, which requires shifting existing trailing elements to the right.
- Deletion (āĻ āĻĒāϏāĻžāϰāĻŖ): Removing an existing data element from a specified index and shifting all subsequent elements to the left to preserve continuity.
- Searching (āĻ āύā§āϏāύā§āϧāĻžāύ): Finding the location or index of a target value (key) using algorithms such as Linear Search or Binary Search.
- Sorting (āĻā§āϰāĻŽāĻžāύā§āϏāĻžāϰ⧠āϏāĻžāĻāĻžāύā§): Rearranging the elements in a specified logical order, ascending or descending (e.g., Bubble Sort, Insertion Sort, Quick Sort).
- Merging (āĻāĻāϤā§āϰā§āĻāϰāĻŖ): Combining two distinct sorted linear arrays into a single, unified sorted array.
2. Explain how a linear array is represented in memory. What is meant by the base address and the word size?Âļ
Question 2: Explain how a linear array is represented in memory. What is meant by the base address and the word size?
Because physical memory (RAM) is organized as a one-dimensional sequence of byte addresses, a linear array is allocated a continuous block of consecutive memory cells. This enables direct, constant-time \(\mathcal{O}(1)\) random access to any element using its index.
Array Memory Layout:
+------------------+------------------+------------------+-----
| A[LB] | A[LB+1] | A[LB+2] | ...
+------------------+------------------+------------------+-----
^ ^
Base(A) Base(A) + w
Address Calculation Formula:
The physical memory address \(\text{LOC}(A[K])\) of the \(K\)-th element is calculated as:
- Base Address (\(\text{Base}(A)\)) (āĻāĻŋāϤā§āϤāĻŋ āĻ āĻŋāĻāĻžāύāĻž): The starting physical memory address of the very first element (\(A[\text{LB}]\)) of the array. It serves as the primary reference point from which all other element addresses are calculated via offsets.
- Word Size (\(w\)) (āĻāĻĒāĻžāĻĻāĻžāύ āĻĒā§āϰāϤāĻŋ āĻŽā§āĻŽāϰāĻŋ āĻŦāĻžāĻāĻ / āĻĄā§āĻāĻž āĻāĻžāĻāĻĒā§āϰ āĻāĻāĻžāϰ): The number of memory bytes required to store a single data element of that type (e.g., \(w = 4\text{ bytes}\) for a standard 32-bit integer, \(w = 8\text{ bytes}\) for a 64-bit float).
- \(\text{LB}\) (Lower Bound / āύāĻŋāĻŽā§āύāϏā§āĻŽāĻž): The lowest index of the array (typically \(0\) in C/C++/Java, or \(1\) in mathematical pseudocode).
Example 1: Mathematical Calculation
Given an integer array \(A\) where:
- \(\text{Base}(A) = 1000\)
- Word size \(w = 4\text{ bytes}\) (integer size)
- \(\text{LB} = 0\)
- Find the location of \(A[3]\) (\(K = 3\)):
Example 2: C Implementation
#include <stdio.h>
int main() {
// Array with Base Index (LB) = 0, Word Size (w) = sizeof(int) = 4 bytes
int A[5] = {10, 20, 30, 40, 50};
// Base Address: LOC(A[0])
printf("Base Address (A[0]): %p\n", (void*)&A[0]);
// Address of A[3]: Base(A) + 4 * (3 - 0) = Base(A) + 12 bytes offset
printf("Address of A[3]: %p\n", (void*)&A[3]);
return 0;
}
3. Write down the concept of the binary search technique. What is the limitation of binary search?Âļ
Concept of Binary Search:Âļ
Binary Search is a divide-and-conquer (āĻŦāĻŋāĻāĻžāĻāύ āĻ āĻŦāĻŋāĻāϝāĻŧ āĻĒāĻĻā§āϧāϤāĻŋ) search algorithm designed strictly for sorted datasets. Rather than examining elements sequentially, it reduces the search space by half in every iteration:
Step 1: Compute MID = (BEG + END) / 2
[ BEG . . . . . . . . MID . . . . . . . . END ]
^
Step 2a: If Target == A[MID] -> Match Found (Terminate)
Step 2b: If Target < A[MID] -> Narrow to Left Half (END = MID - 1)
Step 2c: If Target > A[MID] -> Narrow to Right Half (BEG = MID + 1)
- Initialize boundary pointers: \(\text{BEG} = \text{LB}\) and \(\text{END} = \text{UB}\).
- Calculate the middle index: \(\text{MID} = \lfloor (\text{BEG} + \text{END}) / 2 \rfloor\).
- Compare the target key with \(A[\text{MID}]\):
- If \(A[\text{MID}] == \text{Target}\), return \(\text{MID}\) (Search successful).
- If \(\text{Target} < A[\text{MID}]\), search the left subarray by setting \(\text{END} = \text{MID} - 1\).
-
If \(\text{Target} > A[\text{MID}]\), search the right subarray by setting \(\text{BEG} = \text{MID} + 1\).
-
Repeat steps 2â3 until \(\text{BEG} > \text{END}\) (Target absent).
-
Time Complexity: Worst and average case \(\mathcal{O}(\log_2 n)\), best case \(\mathcal{O}(1)\).
Limitations of Binary Search:Âļ
- Mandatory Sorted Order (āĻŦāĻžāϧā§āϝāϤāĻžāĻŽā§āϞāĻ āĻŦāĻžāĻāĻžāĻāĻā§āϤ āĻā§āϰāĻŽ): The dataset must be sorted beforehand. Sorting an unsorted array takes \(\mathcal{O}(n \log n)\), which makes binary search inefficient for a single search operation.
- Direct Access Dependency: It requires \(\mathcal{O}(1)\) random access to calculate midpoints; it cannot operate efficiently on linked lists (\(\mathcal{O}(n)\) midpoint traversal).
- High Maintenance Cost: Dynamic collections subject to frequent insertions and deletions incur heavy overhead to maintain sorted order.
4. Differentiate between linear search and binary search.Âļ
| Evaluation Metric | Linear Search (āĻ āύā§āĻā§āϰāĻŽāĻŋāĻ āĻ āύā§āϏāύā§āϧāĻžāύ) | Binary Search (āĻĻā§āĻŦāĻŋāĻŽā§āĻā§ āĻ āύā§āϏāύā§āϧāĻžāύ) |
|---|---|---|
| Prerequisite Condition (āĻĒā§āϰā§āĻŦāĻļāϰā§āϤ) | Works on both sorted and unsorted arrays. | Array must be strictly sorted. |
| Search Strategy | Sequential pass (āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻāĻĒāĻžāĻĻāĻžāύā§āϰ āϏāĻžāĻĨā§ āĻāĻā§āϰ āĻĒāϰ āĻāĻ āϤā§āϞāύāĻž). | Divide and conquer (āĻĒā§āϰāϤāĻŋ āϧāĻžāĻĒā§ āĻ āύā§āϏāύā§āϧāĻžāύ āĻĒāϰāĻŋāϏāϰ āĻ āϰā§āϧā§āĻā§ āϰā§āĻĒāĻžāύā§āϤāϰ). |
| Best-Case Complexity | \(\mathcal{O}(1)\) (Target is at the first index). | \(\mathcal{O}(1)\) (Target is at the exact middle index). |
| Worst-Case Complexity | \(\mathcal{O}(n)\) (Target is at the end or absent). | \(\mathcal{O}(\log_2 n)\). |
| Average-Case Complexity | \(\mathcal{O}(n)\). | \(\mathcal{O}(\log_2 n)\). |
| Data Structure Support | Compatible with Arrays and Linked Lists. | Primarily suitable for contiguous Arrays. |
| Algorithm Complexity | Very simple logic; minimal control overhead. | Moderate complexity; requires index bounds tracking. |
5. Explain how the bubble sort technique works, and state why it is given that name.Âļ
Mechanism of Bubble Sort:Âļ
Bubble Sort is an elementary comparison-based algorithm that sorts an array of \(n\) elements over \(n-1\) passes:
- In each pass \(i\), adjacent (āĻĒāĻžāϰā§āĻļā§āĻŦāĻŦāϰā§āϤā§) elements \(A[j]\) and \(A[j+1]\) are compared sequentially from index \(0\) up to \(n - i - 1\).
- If \(A[j] > A[j+1]\), they are swapped (āĻ āĻĻāϞāĻŦāĻĻāϞ āĻāϰāĻž āĻšā§).
- At the end of pass \(i\), the \(i\)-th largest element has moved into its correct final position at the end of the array.
- An optimization boolean flag (
swapped) can terminate execution early if a full pass completes without swaps, achieving \(\mathcal{O}(n)\) best-case time for already-sorted input.
Pass 1 Trace:
[ 5 | 1 | 4 | 2 ] -> Compare (5,1) -> Swap -> [ 1 | 5 | 4 | 2 ]
-> Compare (5,4) -> Swap -> [ 1 | 4 | 5 | 2 ]
-> Compare (5,2) -> Swap -> [ 1 | 4 | 2 | 5 ] (5 placed at end)
Origin of the Name:Âļ
The algorithm is named after the physical behavior of air bubbles rising in water. During each pass, smaller (lighter) elements gradually "bubble up" toward the lower indices (the top), while larger (heavier) elements settle ("sink") to the higher indices at the end of the array.
6. Explain why insertion into and deletion from the middle of a linear array are costly operations.Âļ
Linear arrays require contiguous memory allocation (āĻ āĻŦāĻŋāĻā§āĻāĻŋāύā§āύ āĻŽā§āĻŽāϰāĻŋ āĻŦāĻŖā§āĻāύ). The physical positions of elements correspond directly to their sequential indices, leaving no empty slots between valid data items.
INSERTION AT INDEX 2 (Element: 99):
Original: [ 10 ][ 20 ][ 30 ][ 40 ][ 50 ]
Shift Right: [ 10 ][ 20 ][ -- ][ 30 ][ 40 ][ 50 ] <-- (30, 40, 50 shifted right)
Final: [ 10 ][ 20 ][ 99 ][ 30 ][ 40 ][ 50 ]
DELETION AT INDEX 2:
Original: [ 10 ][ 20 ][ 99 ][ 30 ][ 40 ][ 50 ]
Shift Left: [ 10 ][ 20 ][ 30 ][ 40 ][ 50 ] <-- (30, 40, 50 shifted left)
- Data Shifting Overhead (āĻŽā§āĻŽāϰāĻŋ āϏā§āĻĨāĻžāύāĻā§āϝā§āϤāĻŋ):
- Insertion at Index \(K\): To insert an element at index \(K\), all \((n - K)\) elements from index \(K\) through \(n-1\) must be shifted one position to the right to open a vacancy.
-
Deletion at Index \(K\): To remove an element from index \(K\), all \((n - K - 1)\) elements from index \(K+1\) through \(n-1\) must be shifted one position to the left to close the gap.
-
Algorithmic Cost: In the worst case (modifications at index \(0\)), all \(n\) elements must be shifted. On average, \(n/2\) shifts are required, resulting in an expensive \(\mathcal{O}(n)\) time complexity.
7. What are the advantages and disadvantages of using arrays?Âļ
Advantages:Âļ
- Fast \(\mathcal{O}(1)\) Random Access: Any element can be read or modified in constant time using its index: \(\text{LOC}(A[K]) = \text{Base} + w \cdot (K - \text{LB})\).
- Cache Locality Optimization (āĻŽā§āĻŽāϰāĻŋ āĻā§āϝāĻžāĻļ āĻŦā§āϝāĻŦāĻšāĻžāϰā§āϰ āϏā§āĻŦāĻŋāϧāĻž): Because elements are stored in contiguous memory, arrays benefit from spatial locality (āϏā§āĻĨāĻžāύāĻŋāĻ āĻŽā§āĻŽāϰāĻŋ āύā§āĻāĻā§āϝ), maximizing CPU cache hits and data pre-fetching.
- Zero Pointer Overhead: Arrays do not require auxiliary link pointers (āĻĒāϝāĻŧā§āύā§āĻāĻžāϰ āĻŽā§āĻŽāϰāĻŋ āĻ āĻĒāĻāϝāĻŧ āύā§āĻ), using memory purely for data.
Disadvantages:Âļ
- Static Size Allocation (āϏā§āĻĨāĻŋāϰ āϧāĻžāϰāĻŖāĻā§āώāĻŽāϤāĻž): Array capacity must be fixed in advance. Resizing requires allocating a new memory block and copying all elements (\(\mathcal{O}(n)\) cost).
- Costly Insertions and Deletions: Modifying elements anywhere other than the end requires shifting adjacent elements, incurring \(\mathcal{O}(n)\) time complexity.
- Memory Inefficiency: Oversized arrays lead to internal fragmentation (āĻ āĻā§āϝāύā§āϤāϰā§āĻŖ āĻŽā§āĻŽāϰāĻŋ āĻ āĻĒāĻā§), while undersized arrays risk overflow.
8. Explain the difference between row-major order and column-major order representation of a two dimensional array.Âļ
Computer memory is inherently a one-dimensional array of addresses. A two-dimensional matrix \(A[M \times N]\) (\(M\) rows, \(N\) columns) must be mapped into this linear address space using one of two ordering schemes.
2D Matrix:
[ A[0][0] A[0][1] ]
[ A[1][0] A[1][1] ]
Row-Major: | A[0][0] | A[0][1] | A[1][0] | A[1][1] | (Row-by-Row)
Column-Major: | A[0][0] | A[1][0] | A[0][1] | A[1][1] | (Column-by-Column)
Row-Major Order (RMO) (āϏāĻžāϰāĻŋ-āĻĒā§āϰāϧāĻžāύ āĻā§āϰāĻŽ):Âļ
- Concept: Elements are stored row by row. All elements of Row 0 are placed first, followed by Row 1, Row 2, etc. (Used in C, C++, Java, Python).
- Address Calculation Formula:
(where \(N = \text{total columns}\), \(\text{LB}_r = \text{row lower bound}\), \(\text{LB}_c = \text{column lower bound}\)).
Column-Major Order (CMO) (āĻāϞāĻžāĻŽ-āĻĒā§āϰāϧāĻžāύ āĻā§āϰāĻŽ):Âļ
- Concept: Elements are stored column by column. All elements of Column 0 are placed first, followed by Column 1, Column 2, etc. (Used in Fortran, MATLAB, R).
- Address Calculation Formula:
(where \(M = \text{total rows}\)).
9. Define sparse matrix.Âļ
A sparse matrix is a matrix in which the vast majority of elements have a value of zero.
Sparse Matrix Representation:
[ 0 0 0 5 0 ]
[ 0 0 0 0 0 ]
[ 8 0 0 0 0 ] --> Stored as 3-Tuple to save memory.
[ 0 0 3 0 0 ]
[ 0 0 0 0 0 ]
- Condition: A matrix of size \(M \times N\) containing \(Z\) zero entries and \(NZ\) non-zero entries is defined as sparse when \(NZ \ll (M \times N)\) (typically non-zero entries account for under 15% to 20% of total elements).
- Storage Inefficiency: Storing a sparse matrix as a standard 2D array wastes memory on redundant zeros and leads to inefficient \(\mathcal{O}(M \cdot N)\) computations.
- Triplet (3-Tuple / Coordinate) Representation:
To optimize space and computation, only non-zero entries are stored as triplets: \(\langle \text{Row Index}, \text{Column Index}, \text{Value} \rangle\), preceded by a metadata header indicating total rows, total columns, and total non-zero elements.
| Row Index | Column Index | Value |
|---|---|---|
| 5 (Total Rows) | 5 (Total Cols) | 3 (Total Non-Zero) |
| 0 | 3 | 5 |
| 2 | 0 | 8 |
| 3 | 2 | 3 |
1. Define linear linked list. Explain the process of inserting an element into a linked list with a suitable example.Âļ
A linear linked list is a dynamic, linear data structure in which elements (called nodes) are allocated non-contiguously (āĻ āϏāĻāϞāĻā§āύ / āĻŦāĻŋāĻā§āώāĻŋāĻĒā§āϤ āĻŽā§āĻŽāϰāĻŋāϤā§) in memory. Each node consists of two essential parts:
INFO(orDATA): Stores the actual data element.NEXT(orLINK): A pointer (āύāĻŋāϰā§āĻĻā§āĻļāĻ) holding the physical memory address of the next consecutive node.
A pointer variable START (or HEAD) stores the address of the first node, and the NEXT field of the terminal node contains a NULL (āĻŦāĻž āĻļā§āύā§āϝ āύāĻŋāϰā§āĻĻā§āĻļāĻ) pointer.
+-------------+ +-------------+ +-------------+
START | INFO | NEXT | | INFO | NEXT | | INFO | NEXT |
-----> | 10 | *--|----> | 20 | *--|----> | 30 | NULL |
+-------------+ +-------------+ +-------------+
Process of Inserting an Element (Insertion After a Given Node LOC):Âļ
To insert a new node containing value ITEM immediately after a given node at address LOC:
Before Insertion:
... -> [ Node LOC: 20 | * ] -------------> [ Node: 30 | NULL ]
Step 1 & 2: Allocate NEW node [ ITEM: 25 | NULL ]
Step 3: Point NEW->NEXT to LOC->NEXT (Node 30)
Step 4: Point LOC->NEXT to NEW node
After Insertion:
... -> [ Node LOC: 20 | * ] [ Node: 30 | NULL ]
\ ^
\--> [ NEW: 25 | * ] ---/
- Step 1 (Memory Allocation): Allocate a new node
NEWfrom the free storage pool (AVAILlist / heap memory). If no memory is available, signal Overflow (āϧāĻžāϰāĻŖāĻā§āώāĻŽāϤāĻž āĻāĻĒāĻā§ āĻĒā§āĻž) and terminate. - Step 2 (Assign Data): Set
INFO[NEW] = ITEM. - Step 3 (Re-link Successor): Point the
NEXTpointer of the new node to the logical successor (āĻĒāϰāĻŦāϰā§āϤ⧠āύā§āĻĄ) ofLOC:
- Step 4 (Re-link Predecessor): Update the
NEXTpointer of nodeLOCto reference the newly allocated node:
- Time Complexity: \(\mathcal{O}(1)\) constant time if the pointer
LOCis already known; \(\mathcal{O}(n)\) if searching forLOCis required.
2. Explain the process of deleting an element from a linked list. Which cases must be considered?Âļ
The deletion process removes a target node from the logical sequence by adjusting the pointers of adjacent (āĻĒāĻžāϰā§āĻļā§āĻŦāĻŦāϰā§āϤā§) nodes and returning the unlinked node to the dynamic memory pool (AVAIL list).
Unlinking an Intermediate Node:
+-------------------------------------+
| |
v |
... -> [ Node LOCP: 10 | * ] [ Node LOC: 20 | * ] [ Node: 30 | NULL ]
\__________________/
(To be deleted)
Steps in Deletion:Âļ
- Locate the target node (
LOC) and track its immediate predecessor (āĻĒā§āϰā§āĻŦāĻŦāϰā§āϤ⧠āύā§āĻĄ,LOCP). - Update the pointer of
LOCPto bypass (āĻŦāĻžāĻāĻĒāĻžāϏ āĻāϰāĻž / āĻā§āĻŋā§ā§ āϝāĻžāĻā§āĻž)LOCand directly point toLOC's successor:
- Deallocate (āĻŽā§āĻŽāϰāĻŋ āĻŽā§āĻā§āϤ āĻāϰāĻž) node
LOCby returning it to theAVAILlist.
Cases That Must Be Considered:Âļ
- Case 1: Underflow Condition (
START == NULL): Attempting to delete from an already empty list. Must terminate with an error. - Case 2: Deletion of the First Node (
LOC == START): The list anchorSTARTmust be shifted directly to the second node:
- Case 3: Deletion of an Intermediate Node: Normal pointer reassignment using predecessor
LOCP:
- Case 4: Deletion of the Last Node (Tail Node): The predecessor's link must be set to
NULL:
- Case 5: Target Element Not Found: Traversal reaches
NULLwithout locating the key; issue an appropriate "Item Absent" signal.
3. Define doubly linked list. What are its advantages and disadvantages compared with a singly linked list?Âļ
A doubly linked list (or two-way list) is a linear data structure in which each node contains three fields:
INFO: The payload / actual data value.FORW(orNEXT): Pointer to the successor node.BACK(orPREV): Pointer to the predecessor node.
+-----------------------+-----------------------+
| | |
NULL <-- [ BACK | INFO | FORW ] <-> [ BACK | INFO | FORW ] --> NULL
Advantages Over Singly Linked List:Âļ
- Bidirectional Traversal (āĻĻā§āĻŦāĻŋāĻŽā§āĻā§ āĻĒāϰāĻŋāĻā§āϰāĻŽāĻŖ): The list can be navigated forward (
FORW) and backward (BACK) with equal efficiency. - \(\mathcal{O}(1)\) Deletion Given Node Pointer: A node can delete itself without traversing from
STARTto locate its predecessor, becausenode->BACKdirectly gives the previous node:
- Efficient Predecessor Insertion: Inserting a new node immediately before a given node takes \(\mathcal{O}(1)\) time.
Disadvantages Compared to Singly Linked List:Âļ
- Increased Memory Overhead (āĻ āϤāĻŋāϰāĻŋāĻā§āϤ āĻŽā§āĻŽāϰāĻŋ āĻ āĻĒāĻā§): Every node requires space for two pointer variables instead of one.
- Complex Pointer Maintenance: Operations (insertion, deletion) require updating \(4\) pointers instead of \(2\), increasing code complexity and execution overhead.
4. Write the definition of a header linked list and a two-way linked list with examples.Âļ
Header Linked List:Âļ
A header linked list contains a dedicated, special node at the beginning called the Header Node (āĻŦāĻž āĻļā§āϰā§āώ āύā§āĻĄ). The START pointer always points to this header node, while the actual data elements begin from the node immediately following it.
- Grounded Header List (āϏā§āĻŽāĻžāĻŦāĻĻā§āϧ āĻšā§āĻĄāĻžāϰ āϞāĻŋāϏā§āĻ): The last node's
NEXTpointer containsNULL. - Circular Header List (āĻŦā§āϤā§āϤāĻžāĻāĻžāϰ āĻšā§āĻĄāĻžāϰ āϞāĻŋāϏā§āĻ): The last node's
NEXTpointer points back to the Header Node.
Circular Header Linked List Example:
+------------------------------------------------------+
| |
v |
START -> [ HEADER | * ] -> [ 'A' | * ] -> [ 'B' | * ] -> [ 'C' | * -+ ]
(Count = 3)
Two-Way (Doubly) Linked List:Âļ
A two-way linked list is a linked data structure where each node maintains explicit forward and backward links to facilitate bidirectional traversal.
Two-Way Linked List Example:
+-------------------+ +-------------------+
START | PREV | INFO | NEXT| | PREV | INFO | NEXT|
-----> | NULL | 100 | * -|---->| * | 200 | NULL|
+-------------------+<----+-------------------+
5. Explain the terms garbage collection, overflow and underflow with reference to linked lists.Âļ
- Garbage Collection (āĻ āĻŦā§āϝāĻŦāĻšā§āϤ āĻŽā§āĻŽāϰāĻŋ āĻĒā§āύāϰā§āĻĻā§āϧāĻžāϰ / āϏāĻāĻā§āϰāĻš):
- Concept: When nodes are deleted or unlinked from a linked list, their physical memory cells remain allocated unless explicitly freed. Garbage collection is the operating system or runtime mechanism that identifies these orphaned (āϏāĻāϝā§āĻāĻšā§āύ) memory blocks and returns them to the free storage pool (
AVAILlist). -
Significance: Prevents memory leaks (āĻŽā§āĻŽāϰāĻŋ āĻā§āώāϝāĻŧ) during prolonged execution of programs with high dynamic allocations.
-
Overflow (āϧāĻžāϰāĻŖāĻā§āώāĻŽāϤāĻž āĻāĻĒāĻā§ āĻĒā§āĻž):
- Concept: Occurs during an insertion operation when the system attempts to allocate memory for a new node, but the free storage list is empty (
AVAIL == NULL) due to complete physical memory exhaustion. -
Condition: \(\text{AVAIL} = \text{NULL} \implies \text{Overflow Error}\).
-
Underflow (āĻļā§āύā§āϝāϤāĻžāĻŦāϏā§āĻĨāĻž / āĻāĻĒāĻžāĻĻāĻžāύ āĻ āĻĒā§āϰāϤā§āϞāϤāĻž):
- Concept: Occurs during a deletion operation when an algorithm attempts to remove a node from an already empty linked list (
START == NULL). - Condition: \(\text{START} = \text{NULL} \implies \text{Underflow Error}\).
6. Differentiate between an array and a linked list.Âļ
| Evaluation Metric | Array (āĻ ā§āϝāĻžāϰā§) | Linked List (āϏāĻāϝā§āĻā§āϤ āϤāĻžāϞāĻŋāĻāĻž) |
|---|---|---|
| Memory Allocation | Static / Contiguous: Fixed size allocated in continuous memory blocks. | Dynamic / Non-contiguous: Nodes allocated at runtime across scattered heap memory. |
| Element Access Time | Direct \(\mathcal{O}(1)\) random access using index. | Sequential \(\mathcal{O}(n)\) access via pointer traversal. |
| Insertion / Deletion Cost | Expensive \(\mathcal{O}(n)\) due to physical shifting of elements. | Efficient \(\mathcal{O}(1)\) once the pointer location is identified (no shifting). |
| Memory Overhead | Zero: Space is used strictly for data values. | High: Each node requires auxiliary (āϏāĻšāĻžāϝāĻŧāĻ) pointer storage (NEXT, PREV). |
| Cache Locality (āĻā§āϝāĻžāĻļ āύā§āĻāĻā§āϝ) | Excellent spatial locality; maximizes CPU cache hits. | Poor spatial locality; nodes distributed across heap cause cache misses. |
| Resizing Flexibility | Fixed capacity; dynamic expansion requires reallocation and copying. | Fully dynamic; grows and shrinks node-by-node seamlessly. |
7. Why is a linked list called a dynamic data structure? Explain its advantages over an array.Âļ
Why It Is Called a Dynamic Data Structure:Âļ
A linked list is termed dynamic because its memory footprint (āĻŽā§āĻŽāϰāĻŋ āĻĒāϰāĻŋāϏāϰ) is not predetermined at compile-time. Instead, memory is allocated and released individually for each node at runtime (āĻĒā§āϰā§āĻā§āϰāĻžāĻŽ āĻāϞāĻžāĻāĻžāϞā§āύ āϏāĻŽā§ā§) directly from the system heap using operations like malloc() or new. It expands when elements are added and contracts when elements are removed without needing bulk block allocations.
Advantages Over an Array:Âļ
- No Pre-allocation Waste (āĻŽā§āĻŽāϰāĻŋ āĻ āĻĒāĻā§ āϰā§āϧ): Eliminates internal fragmentation since there is no requirement to declare a fixed maximum capacity in advance.
- Constant-Time Insertion and Deletion: Inserting or deleting a node at a known location requires only adjusting link pointers (\(\mathcal{O}(1)\)), completely avoiding the costly element-shifting operations (\(\mathcal{O}(n)\)) typical of arrays.
- Efficient Utilization of Fragmented Memory: Since contiguous physical blocks are not required, a linked list can utilize non-contiguous memory segments that would otherwise be unusable for large arrays.
8. Explain the purpose of the header node in a header linked list.Âļ
The header node is placed at index \(0\) of the list to streamline algorithmic design and record global metadata:
- Elimination of Boundary / Special Cases (āĻĒā§āϰāĻžāύā§āϤāĻŋāĻ āĻļāϰā§āϤ āϏāĻšāĻā§āĻāϰāĻŖ):
- In a standard linked list, inserting or deleting the very first node requires modifying the global
STARTpointer itself. - In a header linked list,
STARTpermanently points to the invariant (āĻ āĻĒāϰāĻŋāĻŦāϰā§āϤāύā§ā§) header node. All insertions and deletionsâeven at the logical beginning of the data sequenceâoccur after the header node, removing the need for separate edge-case logic forSTART.
Standard List Insertion at Beginning: Requires modifying master START pointer
Header List Insertion at Beginning: Standard insertion after Header node (No START modification)
- Metadata Repository (āĻŽā§āĻāĻžāĻĄā§āĻāĻž āϏāĻāϰāĻā§āώāĻŖ):
TheINFOfield of the header node can store global summary information about the list, including: - Total node count (allowing \(\mathcal{O}(1)\) length queries).
- Pointers to the maximum/minimum data values.
-
Timestamp or list status flags.
-
Simplification of Circular Traversal: In circular header lists, the header node provides an unambiguous anchor point to detect when a full loop traversal has completed.