0% found this document useful (0 votes)
3 views35 pages

C Programming and Data Structures 41394658 2025 06-20-08 20

The document provides a comprehensive overview of data structures, categorizing them into primitive and non-primitive types, and detailing linear and non-linear structures such as arrays, linked lists, trees, and graphs. It also covers searching and sorting algorithms, including linear search, binary search, bubble sort, and quick sort, along with their time complexities and example codes. Additionally, it discusses linked storage representation and specifically focuses on the stack data structure, emphasizing its Last In, First Out (LIFO) principle.

Uploaded by

guynani53
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)
3 views35 pages

C Programming and Data Structures 41394658 2025 06-20-08 20

The document provides a comprehensive overview of data structures, categorizing them into primitive and non-primitive types, and detailing linear and non-linear structures such as arrays, linked lists, trees, and graphs. It also covers searching and sorting algorithms, including linear search, binary search, bubble sort, and quick sort, along with their time complexities and example codes. Additionally, it discusses linked storage representation and specifically focuses on the stack data structure, emphasizing its Last In, First Out (LIFO) principle.

Uploaded by

guynani53
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/ 35

DATA STRUCTURES THROUGH C

INTODUCTION TO DATA STRUCTURES:


Data Structure
A data structure is a specialized format for organizing, processing, and storing data. It defines
a way to manage and organize data efficiently to support various operations, such as
insertion, deletion, and retrieval.

Types of Data Structures


Data structures can be broadly categorized into two types:
• Primitive Data Structures: Basic data types provided by programming languages.
Examples include integers, floats, characters, and booleans.
• Non-Primitive Data Structures: More complex structures built using primitive data
types. These can be further classified into:
o Linear Data Structures
o Non-Linear Data Structures
o Hash-Based Data Structures
o Tree-Based Data Structures
Linear Data Structures
Linear data structures organize data in a sequential manner. Common linear data structures
include:
• Arrays:
o Description: A collection of elements, all of the same type, stored in
contiguous memory locations.
o Operations: Accessing elements by index, insertion, deletion, and traversal.
o Example: int arr[5] = {1, 2, 3, 4, 5};
• Linked Lists:
o Description: A collection of nodes where each node contains data and a
reference (link) to the next node.
o Types:
▪ Singly Linked List: Each node points to the next node.
▪ Doubly Linked List: Each node points to both the next and previous
nodes.
▪ Circular Linked List: The last node points back to the first node.
o Operations: Insertion, deletion, traversal, and searching.
• Stacks:
o Description: A collection of elements with Last In, First Out (LIFO) access
order.
o Operations: Push (insert), Pop (remove), Peek (retrieve top element), and
isEmpty.
o Example: Function call stack in recursion.
• Queues:
o Description: A collection of elements with First In, First Out (FIFO) access
order.
o Types:
▪ Simple Queue: Basic FIFO queue.
▪ Circular Queue: The last position is connected back to the first
position.
▪ Priority Queue: Elements are removed based on priority rather than
order of insertion.
o Operations: Enqueue (insert), Dequeue (remove), and Peek (retrieve front
element).
Non-Linear Data Structures
Non-linear data structures do not organize data in a sequential manner. Common non-linear
data structures include:
• Trees:
o Description: A hierarchical structure with a root node and child nodes forming
a parent-child relationship.
o Types:
▪ Binary Tree: Each node has at most two children.
▪ Binary Search Tree (BST): A binary tree where the left child’s value is
less than the parent node’s value and the right child’s value is greater.
▪ AVL Tree: A self-balancing binary search tree where the difference in
heights between left and right subtrees is at most one.
▪ Heap: A complete binary tree where each node follows a specific heap
property (min-heap or max-heap).
o Operations: Insertion, deletion, traversal (pre-order, in-order, post-order).
• Graphs:
o Description: A collection of nodes (vertices) connected by edges. Useful for
representing networks and relationships.
o Types:
▪ Directed Graph: Edges have a direction.
▪ Undirected Graph: Edges do not have a direction.
▪ Weighted Graph: Edges have weights (costs).
▪ Unweighted Graph: Edges do not have weights.
o Operations: Traversal (BFS, DFS), shortest path (Dijkstra’s, Bellman-Ford),
and minimum spanning tree (Kruskal’s, Prim’s).
Hash-Based Data Structures
Hash-based data structures use hash functions to map keys to positions in a table. They
provide efficient access and retrieval operations.
• Hash Tables:
o Description: A data structure that uses a hash function to compute an index
into an array of buckets or slots.
o Operations: Insertion, deletion, and search.
o Collision Resolution Techniques: Chaining (linked lists), Open Addressing
(linear probing, quadratic probing).
Tree-Based Data Structures
Tree-based structures are used to model hierarchical relationships and support efficient
searching and sorting.
• Binary Trees:
o Binary Search Tree (BST): Allows for fast search, insertion, and deletion
operations.
• Balanced Trees:
o AVL Trees: Self-balancing BST where the height difference between left and
right subtrees is no more than one.
o Red-Black Trees: A type of self-balancing BST with specific balancing rules.
• Heaps:
o Min-Heap: The smallest element is at the root, and each parent node is less
than or equal to its children.
o Max-Heap: The largest element is at the root, and each parent node is greater
than or equal to its children.
Key Operations
Common operations performed on data structures include:
• Insertion: Adding a new element.
• Deletion: Removing an existing element.
• Traversal: Accessing each element.
• Search: Finding an element.
• Sorting: Arranging elements in a specific order.
Choosing the Right Data Structure
The choice of data structure depends on the specific needs of the application, such as:
• Time Complexity: How quickly operations can be performed.
• Space Complexity: How much memory is used.
• Use Case: Specific requirements such as hierarchical data, fast lookups, or ordered
data.
SEARCHING AND SORTING :

1. Searching Algorithms
Searching algorithms are used to find the position of a specific element within a data
structure.
1.1 Linear Search
• Description: Checks each element in the list sequentially until the desired element is
found or the list ends.
• Time Complexity: O(n) - where nnn is the number of elements in the list.
• Use Case: Suitable for unsorted or small datasets.
• Example Code:
def linear_search(arr, target):
for index, value in enumerate(arr):
if value == target:
return index
return -1
1.2 Binary Search
• Description: Efficiently finds an element in a sorted list by repeatedly dividing the
search interval in half.
• Time Complexity: O(log n) - where nnn is the number of elements in the list.
• Use Case: Requires the list to be sorted beforehand.
• Example Code:
def binary_search(arr, target):
low, high = 0, len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
2. Sorting Algorithms
Sorting algorithms are used to arrange elements in a specific order, typically ascending or
descending.
2.1 Bubble Sort
• Description: Repeatedly steps through the list, compares adjacent elements, and
swaps them if they are in the wrong order.
• Time Complexity: O(n^2) - where nnn is the number of elements in the list.
• Use Case: Simple to implement but inefficient for large lists.
• Example Code:
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
2.2 Selection Sort
• Description: Divides the list into a sorted and an unsorted region. Repeatedly selects
the smallest (or largest) element from the unsorted region and moves it to the sorted
region.
• Time Complexity: O(n^2) - where nnn is the number of elements in the list.
• Use Case: Simple and intuitive, but inefficient for large datasets.
• Example Code:
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_index = i
for j in range(i+1, n):
if arr[j] < arr[min_index]:
min_index = j
arr[i], arr[min_index] = arr[min_index], arr[i]
2.3 Insertion Sort
• Description: Builds the final sorted list one item at a time. Takes each element from
the input and finds the location it belongs in the sorted list, and inserts it there.
• Time Complexity: O(n^2) - where nnn is the number of elements in the list.
• Use Case: Efficient for small datasets or nearly sorted lists.
• Example Code:
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j=i-1
while j >= 0 and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
2.4 Merge Sort
• Description: Divides the list into halves, recursively sorts each half, and then merges
the sorted halves.
• Time Complexity: O(n log n) - where nnn is the number of elements in the list.
• Use Case: Efficient for large datasets and stable sort.
• Example Code:

def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
left_half = arr[:mid]
right_half = arr[mid:]

merge_sort(left_half)
merge_sort(right_half)

i=j=k=0
while i < len(left_half) and j < len(right_half):
if left_half[i] < right_half[j]:
arr[k] = left_half[i]
i += 1
else:
arr[k] = right_half[j]
j += 1
k += 1

while i < len(left_half):


arr[k] = left_half[i]
i += 1
k += 1

while j < len(right_half):


arr[k] = right_half[j]
j += 1
k += 1
2.5 Quick Sort
• Description: Selects a 'pivot' element, partitions the list into elements less than and
greater than the pivot, and recursively sorts the partitions.
• Time Complexity: O(n log n) average, O(n^2) worst-case.
• Use Case: Efficient for large datasets and generally faster than merge sort.
• Example Code:
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
2.6 Heap Sort
• Description: Converts the list into a heap structure and repeatedly extracts the
maximum element to build a sorted list.
• Time Complexity: O(n log n) - where nnn is the number of elements in the list.
• Use Case: Efficient for large datasets and in-place sorting.
• Example Code:
def heapify(arr, n, i):
largest = i
left = 2 * i + 1
right = 2 * i + 2

if left < n and arr[i] < arr[left]:


largest = left
if right < n and arr[largest] < arr[right]:
largest = right
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
def heap_sort(arr):
n = len(arr)
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i]
heapify(arr, i, 0)
LINKED STORAGE REPRESENTATION:

Linked Storage Representation is a method of organizing data in which elements are stored in
nodes that are connected through links. This approach is often used in various data structures
like linked lists, trees, and graphs. Unlike arrays, where elements are stored in contiguous
memory locations, linked storage allows for more flexible data management by dynamically
allocating memory.
Key Concepts of Linked Storage Representation
1. Nodes and Links
• Node: The basic unit of storage in a linked structure. Each node typically contains:
o Data: The value or information the node holds.
o Link (Pointer): A reference to the next node in the sequence (in singly linked
lists) or both the next and previous nodes (in doubly linked lists).
2. Types of Linked Lists
1. Singly Linked List
o Description: Each node contains a single link pointing to the next node in the
sequence.
o Structure: Node -> Next Node -> Next Node -> NULL
o Operations:
▪ Insertion: Add nodes at the beginning, end, or between existing nodes.
▪ Deletion: Remove nodes from the beginning, end, or a specific
position.
▪ Traversal: Access nodes sequentially from the head to the end.

o Example Code:
class Node:
def __init__(self, data=None):
self.data = data
self.next = None

class SinglyLinkedList:
def __init__(self):
self.head = None
def append(self, data):
new_node = Node(data)
if self.head is None:
self.head = new_node
return
last = self.head
while last.next:
last = last.next
last.next = new_node

def print_list(self):
current = self.head
while current:
print(current.data, end=" -> ")
current = current.next
print("NULL")
2. Doubly Linked List
o Description: Each node contains two links, one pointing to the next node and
one pointing to the previous node.
o Structure: NULL <- Prev Node <-> Current Node <-> Next Node -> NULL
o Operations: Similar to singly linked lists but allows bidirectional traversal.
o Example Code:
class DoublyNode:
def __init__(self, data=None):
self.data = data
self.next = None
self.prev = None

class DoublyLinkedList:
def __init__(self):
self.head = None

def append(self, data):


new_node = DoublyNode(data)
if self.head is None:
self.head = new_node
return
last = self.head
while last.next:
last = last.next
last.next = new_node
new_node.prev = last

def print_list(self):
current = self.head
while current:
print(current.data, end=" <-> ")
current = current.next
print("NULL")

3. Circular Linked List


o Description: Similar to singly or doubly linked lists but the last node links
back to the first node, forming a circular structure.
o Structure: Node -> Node -> Node -> Head Node
o Operations: Allows for continuous traversal without encountering a NULL
reference.
Example Code:
class CircularNode:
def __init__(self, data=None):
self.data = data
self.next = None

class CircularLinkedList:
def __init__(self):
self.head = None

def append(self, data):


new_node = CircularNode(data)
if self.head is None:
self.head = new_node
new_node.next = self.head
return
last = self.head
while last.next != self.head:
last = last.next
last.next = new_node
new_node.next = self.head

def print_list(self):
current = self.head
if self.head is None:
return
while True:
print(current.data, end=" -> ")
current = current.next
if current == self.head:
break
print("NULL")
LINEAR DATA STRUCTURE -STACKS
Stack Data Structure
A stack is a fundamental linear data structure that follows the Last In, First Out (LIFO)
principle. This means that the last element added to the stack is the first one to be removed.
It’s akin to a stack of plates where you can only take the top plate off or add a new plate on
top.

Key Operations:
1. Push: Add an element to the top of the stack.
2. Pop: Remove the element from the top of the stack.
3. Peek (or Top): Retrieve the element at the top of the stack without removing it.
4. IsEmpty: Check if the stack is empty.
Common Applications:
• Function Call Management: Keeping track of function calls and local variables.
• Expression Evaluation: Evaluating expressions in postfix notation (Reverse Polish
notation).
• Undo Mechanism: Implementing undo operations in software.
Implementation
Stacks can be implemented using arrays or linked lists. Below are implementations for both
methods:
1. Stack Implementation Using Array
Description:
• Uses a fixed-size list (array) to store stack elements.
• Provides constant time complexity for push and pop operations.
Example Code (Python):
class StackArray:
def __init__(self):
self.stack = []

def push(self, item):


self.stack.append(item)

def pop(self):
if not self.is_empty():
return self.stack.pop()
raise IndexError("Pop from empty stack")

def peek(self):
if not self.is_empty():
return self.stack[-1]
raise IndexError("Peek from empty stack")

def is_empty(self):
return len(self.stack) == 0

def print_stack(self):
print(self.stack)

# Example Usage
stack = StackArray()
stack.push(1)
stack.push(2)
print(stack.peek()) # Output: 2
stack.pop()
stack.print_stack() # Output: [1]

2. Stack Implementation Using Linked List


Description:
• Uses nodes linked together to form the stack.
• Each node contains data and a reference to the next node.
• Supports dynamic size.
Example Code (Python):
class Node:
def __init__(self, data):
self.data = data
self.next = None

class StackLinkedList:
def __init__(self):
self.top = None

def push(self, item):


new_node = Node(item)
new_node.next = self.top
self.top = new_node

def pop(self):
if not self.is_empty():
pop_value = self.top.data
self.top = self.top.next
return pop_value
raise IndexError("Pop from empty stack")

def peek(self):
if not self.is_empty():
return self.top.data
raise IndexError("Peek from empty stack")

def is_empty(self):
return self.top is None

def print_stack(self):
current = self.top
while current:
print(current.data, end=" -> ")
current = current.next
print("NULL")

# Example Usage
stack = StackLinkedList()
stack.push(1)
stack.push(2)
print(stack.peek()) # Output: 2
stack.pop()
stack.print_stack() # Output: 1 -> NULL
Complexity Analysis
• Time Complexity:
o Push: O(1) — Adding an element to the stack.
o Pop: O(1) — Removing the top element from the stack.
o Peek: O(1) — Accessing the top element of the stack.
o IsEmpty: O(1) — Checking if the stack is empty.
• Space Complexity:
o Array Implementation: O(n) — Space used is proportional to the number of
elements.
o Linked List Implementation: O(n) — Space used is proportional to the
number of nodes.

Advantages and Disadvantages


Advantages:
• Simple Implementation: Both array and linked list implementations are
straightforward.
• Efficient Operations: Push, pop, and peek operations are O(1), making them very
efficient.
Disadvantages:
• Fixed Size (Array): For the array-based implementation, the size of the stack is fixed
and cannot grow dynamically.
• Memory Overhead (Linked List): The linked list implementation uses extra
memory for storing node pointers.

LINEAR DATA STRUCTURE-QUEUES


Queue Data Structure
A queue is a linear data structure that follows the First In, First Out (FIFO) principle. This
means that the first element added to the queue will be the first one to be removed. This is
similar to a queue in real life, such as a line at a checkout counter, where people are served in
the order they arrive.

Key Operations:
1. Enqueue: Add an element to the rear (end) of the queue.
2. Dequeue: Remove an element from the front of the queue.
3. Peek (or Front): Retrieve the element at the front of the queue without removing it.
4. IsEmpty: Check if the queue is empty.
Common Applications:
• Task Scheduling: Managing tasks in operating systems or print spooling.
• Breadth-First Search (BFS): Traversal algorithm for graphs and trees.
• Buffer Management: Implementing buffers like in IO devices, network packets, etc.
Implementation
Queues can be implemented using arrays, linked lists, or using specialized data structures
such as deque (double-ended queue). Here are implementations for both array and linked list
based queues:
1. Queue Implementation Using Array
Description:
• Uses a fixed-size list (array) to store queue elements.
• Often requires handling of index wrap-around using circular buffer techniques.
Example Code (Python):
class QueueArray:
def __init__(self, size):
self.size = size
self.queue = [None] * size
self.front = 0
self.rear = -1
self.count = 0

def enqueue(self, item):


if self.is_full():
raise OverflowError("Queue is full")
self.rear = (self.rear + 1) % self.size
self.queue[self.rear] = item
self.count += 1

def dequeue(self):
if self.is_empty():
raise IndexError("Dequeue from empty queue")
item = self.queue[self.front]
self.queue[self.front] = None
self.front = (self.front + 1) % self.size
self.count -= 1
return item

def peek(self):
if self.is_empty():
raise IndexError("Peek from empty queue")
return self.queue[self.front]

def is_empty(self):
return self.count == 0

def is_full(self):
return self.count == self.size

def print_queue(self):
if self.is_empty():
print("Queue is empty")
return
i = self.front
while True:
print(self.queue[i], end=" -> ")
if i == self.rear:
break
i = (i + 1) % self.size
print("NULL")
# Example Usage
queue = QueueArray(5)
queue.enqueue(1)
queue.enqueue(2)
print(queue.peek()) # Output: 1
queue.dequeue()
queue.print_queue() # Output: 2 -> NULL
2. Queue Implementation Using Linked List
Description:
• Uses nodes linked together to form the queue.
• Each node contains data and a reference to the next node.
• Supports dynamic size.
Example Code (Python):
class Node:
def __init__(self, data):
self.data = data
self.next = None

class QueueLinkedList:
def __init__(self):
self.front = None
self.rear = None
self.size = 0

def enqueue(self, item):


new_node = Node(item)
if self.is_empty():
self.front = self.rear = new_node
else:
self.rear.next = new_node
self.rear = new_node
self.size += 1

def dequeue(self):
if self.is_empty():
raise IndexError("Dequeue from empty queue")
item = self.front.data
self.front = self.front.next
if self.front is None:
self.rear = None
self.size -= 1
return item

def peek(self):
if self.is_empty():
raise IndexError("Peek from empty queue")
return self.front.data

def is_empty(self):
return self.front is None

def print_queue(self):
current = self.front
while current:
print(current.data, end=" -> ")
current = current.next
print("NULL")

# Example Usage
queue = QueueLinkedList()
queue.enqueue(1)
queue.enqueue(2)
print(queue.peek()) # Output: 1
queue.dequeue()
queue.print_queue() # Output: 2 -> NULL
Complexity Analysis
• Time Complexity:
o Enqueue: O(1) — Adding an element to the rear.
o Dequeue: O(1) — Removing the element from the front.
o Peek: O(1) — Accessing the front element.
o IsEmpty: O(1) — Checking if the queue is empty.
• Space Complexity:
o Array Implementation: O(n) — Space used is proportional to the number of
elements.
o Linked List Implementation: O(n) — Space used is proportional to the number
of nodes.
Advantages and Disadvantages
Advantages:
• Efficient Operations: All primary operations (enqueue, dequeue, peek) are O(1).
• Simple Implementation: Straightforward to implement and use.
Disadvantages:
• Fixed Size (Array): For the array-based implementation, the size of the queue is fixed
and may require resizing.
• Memory Overhead (Linked List): The linked list implementation uses extra memory
for storing node pointers.

NON-LINEAR DATA STRUCTURE-TREES:

Tree Data Structures


Trees are a type of non-linear data structure where elements (nodes) are organized
hierarchically. Unlike linear data structures, trees have a root node from which all other nodes
descend, creating a branching structure.
Key Concepts of Trees
1. Node: The basic unit of a tree that contains data and references (links) to other nodes.
2. Root: The topmost node of the tree, which has no parent.
3. Parent: A node that has one or more child nodes.
4. Child: A node that descends from another node (its parent).
5. Leaf: A node that does not have any children.
6. Subtree: A tree consisting of a node and its descendants.
7. Depth: The length of the path from the root to a node.
8. Height: The length of the longest path from a node to a leaf.

Common Types of Trees


1. Binary Tree
A binary tree is a tree data structure where each node has at most two children: the left child
and the right child.

Properties:
• Full Binary Tree: Every node has either 0 or 2 children.
• Complete Binary Tree: All levels, except possibly the last, are fully filled, and all
nodes are as far left as possible.
• Perfect Binary Tree: All internal nodes have two children, and all leaves are at the
same level.
Example Code (Python):
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None

class BinaryTree:
def __init__(self):
self.root = None

def insert(self, data):


if self.root is None:
self.root = Node(data)
else:
self._insert(self.root, data)

def _insert(self, node, data):


if data < node.data:
if node.left is None:
node.left = Node(data)
else:
self._insert(node.left, data)
else:
if node.right is None:
node.right = Node(data)
else:
self._insert(node.right, data)

def inorder(self):
return self._inorder(self.root)

def _inorder(self, node):


return (self._inorder(node.left) if node.left else []) + [node.data] +
(self._inorder(node.right) if node.right else [])

# Example Usage
tree = BinaryTree()
tree.insert(5)
tree.insert(3)
tree.insert(7)
print(tree.inorder()) # Output: [3, 5, 7]
2. Binary Search Tree (BST)
A binary search tree is a binary tree where each node follows the property that all nodes in the
left subtree are less than the root node, and all nodes in the right subtree are greater.

Operations:
• Search: O(log n) on average.
• Insertion/Deletion: O(log n) on average.
Example Code (Python):
The BinaryTree class above can be used as a Binary Search Tree with minor modifications.
3. AVL Tree
An AVL tree is a self-balancing binary search tree where the difference in heights of left and
right subtrees (balance factor) of any node is at most 1.

Operations:
• Insertion/Deletion: O(log n) due to balancing.
Example Code (Python):
Implementation of AVL Tree requires rotations to maintain balance, which is more complex.
Here's a high-level outline:
class AVLNode:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
self.height = 1

# AVL Tree implementation would require rotation and balancing methods.


4. Red-Black Tree
A red-black tree is a self-balancing binary search tree where each node has an extra bit for
color (red or black) to ensure the tree remains balanced during insertions and deletions.
Properties:
• Balance: Ensures O(log n) time complexity for insertions, deletions, and searches.
Example Code (Python):
A red-black tree implementation involves complex balancing and color-switching logic.
5. B-Tree
A B-tree is a self-balancing tree data structure that maintains sorted data and allows searches,
sequential access, insertions, and deletions in logarithmic time.
Properties:
• Used extensively in databases and file systems.
• Each node can have multiple children and keys.
Example Code (Python):
B-trees are more complex and not typically implemented from scratch due to their detailed
balancing rules.
6. Trie (Prefix Tree)
A trie is a tree-like data structure used for storing a dynamic set of strings where keys are
usually strings. Each node represents a common prefix of some strings.
Operations:
• Insertion/Search: O(m), where m is the length of the string.
Example Code (Python):
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False

class Trie:
def __init__(self):
self.root = TrieNode()

def insert(self, word):


node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end_of_word = True

def search(self, word):


node = self.root
for char in word:
if char not in node.children:
return False
node = node.children[char]
return node.is_end_of_word

# Example Usage
trie = Trie()
trie.insert("hello")
print(trie.search("hello")) # Output: True
print(trie.search("hell")) # Output: False
Complexity Analysis
• Time Complexity for Balanced Trees (e.g., AVL, Red-Black):
o Search/Insert/Delete: O(log n), where n is the number of nodes.
• Time Complexity for Tries:
o Search/Insert: O(m), where m is the length of the key (string).
• Space Complexity:
o Binary Trees: O(n), where n is the number of nodes.
o Tries: O(n * m), where n is the number of words and m is the length of the
average word.
Advantages and Disadvantages
Advantages:
• Efficient Searching/Insertion: Balanced trees ensure logarithmic time complexity for
operations.
• Hierarchical Representation: Natural fit for hierarchical data.
Disadvantages:
• Complexity: Self-balancing trees and tries have complex implementation details.
• Space Overhead: Tries may use significant space due to storing nodes for all prefixes.
IMPORTANT MCQS
1. What is the primary characteristic of a tree data structure?
o A) Linear arrangement
o B) Hierarchical arrangement
o C) Random arrangement
o D) Circular arrangement
Answer: B) Hierarchical arrangement
2. In a binary tree, each node can have at most how many children?
o A) 1
o B) 2
o C) 3
o D) 4
Answer: B) 2
3. What is the maximum number of nodes at level 'L' in a binary tree?
o A) 2^L
o B) 2^(L-1)
o C) 2^(L+1)
o D) 2^(L-2)
Answer: A) 2^L
4. Which of the following is true about a binary search tree (BST)?
o A) All nodes have exactly two children
o B) Left subtree nodes are greater than the root node
o C) Right subtree nodes are smaller than the root node
o D) Left subtree nodes are smaller than the root node, and right subtree nodes
are greater
Answer: D) Left subtree nodes are smaller than the root node, and right subtree nodes are
greater
2. Binary Trees
5. What is the depth of a tree?
o A) The number of nodes in the tree
o B) The length of the path from the root to the deepest leaf
o C) The number of edges from the root to the deepest leaf
o D) The height of the root node
Answer: C) The number of edges from the root to the deepest leaf
6. Which traversal method visits nodes in the order: left subtree, root, right
subtree?
o A) Pre-order
o B) In-order
o C) Post-order
o D) Level-order
Answer: B) In-order
7. What type of binary tree has all levels fully filled except possibly the last one?
o A) Full Binary Tree
o B) Complete Binary Tree
o C) Perfect Binary Tree
o D) Balanced Binary Tree
Answer: B) Complete Binary Tree
8. What is the height of a perfect binary tree with 'n' nodes?
o A) log2(n+1)
o B) log2(n)
o C) log2(n) - 1
o D) log2(n) + 1
Answer: C) log2(n) - 1
3. AVL and Red-Black Trees
9. Which property is maintained in an AVL tree?
o A) All nodes have two children
o B) Height of the left and right subtrees of any node differs by at most 1
o C) All nodes in the right subtree are less than the root node
o D) All nodes in the left subtree are greater than the root node
Answer: B) Height of the left and right subtrees of any node differs by at most 1
10. Which of the following is a key characteristic of a Red-Black tree?
o A) Nodes are colored red or black to ensure balance
o B) Every node has exactly two children
o C) All nodes are always balanced
o D) It’s a self-balancing tree but does not use colors
Answer: A) Nodes are colored red or black to ensure balance
4. Queues
11. In a queue, which operation removes an element from the front?
o A) Enqueue
o B) Dequeue
o C) Peek
o D) Push
Answer: B) Dequeue
12. What is the main advantage of using a circular queue over a linear queue?
o A) It has more space complexity
o B) It can efficiently utilize the available space
o C) It requires more memory
o D) It has slower operations
Answer: B) It can efficiently utilize the available space
13. Which data structure can be implemented using two stacks to create a queue?
o A) Priority Queue
o B) Circular Queue
o C) Deque
o D) FIFO Queue
Answer: D) FIFO Queue
14. What is the time complexity of the enqueue operation in a queue implemented
with a linked list?
o A) O(1)
o B) O(n)
o C) O(log n)
o D) O(n^2)
Answer: A) O(1)
5. Trie and Advanced Trees
15. In a Trie, what does each node represent?
o A) A unique character or prefix
o B) A complete string
o C) A number
o D) A list of strings
Answer: A) A unique character or prefix
16. Which type of tree is used for balancing file directories in a file system?
o A) Binary Tree
o B) AVL Tree
o C) Red-Black Tree
o D) B-Tree
Answer: D) B-Tree
17. What is the main advantage of a B-Tree over a binary search tree?
o A) It has a higher height
o B) It has a larger branching factor, leading to fewer levels
o C) It supports more complex operations
o D) It requires more memory
Answer: B) It has a larger branching factor, leading to fewer levels
18. What operation is used to insert a word into a Trie data structure?
o A) Add
o B) Insert
o C) Push
o D) Store
Answer: B) Insert
6. General Knowledge
19. In which of the following scenarios is a queue most appropriate?
o A) Function call management
o B) Task scheduling
o C) Evaluating mathematical expressions
o D) Implementing undo operations
Answer: B) Task scheduling
20. What does a node's height represent in a tree?
o A) The number of nodes in the subtree
o B) The number of edges from the node to its deepest leaf
o C) The total number of children of the node
o D) The depth of the node in the tree
Answer: B) The number of edges from the node to its deepest leaf

You might also like