Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
3 views

DS-Python-chapter-2-notes

The document provides an overview of linear data structures, focusing on arrays, linked lists, stacks, and queues. It details the characteristics, types, operations, and implementations of arrays and linked lists in Python, including examples for each. Additionally, it compares arrays with lists and outlines the advantages and disadvantages of linked lists.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

DS-Python-chapter-2-notes

The document provides an overview of linear data structures, focusing on arrays, linked lists, stacks, and queues. It details the characteristics, types, operations, and implementations of arrays and linked lists in Python, including examples for each. Additionally, it compares arrays with lists and outlines the advantages and disadvantages of linked lists.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 31

2.

Linear Data Structures

Syllabus :
2.1 Arrays – Overview, Types of Arrays, Operations on Arrays, Arrays vs List
2.2 Linked List – Overview, Implementation of Singly Linked Lists, Doubly Linked
Lists, Circular Linked Lists.
2.3 Stack - Overview of Stack, Implementation of Stack, Applications of Stack
(expression evaluation)
2.4 Queue-Overview of Queue, Implementation of Queue, Applications of Queues,
Types of Queues

2.1 Arrays
An array is a data structure that stores elements of the same data type in contiguous memory
locations. It allows efficient random access and manipulation of elements using their indices.

Features of Arrays
1. Fixed Size: The size of an array is determined at the time of creation and cannot be
modified.
2. Homogeneous Elements: All elements in the array are of the same data type.
3. Indexing: Elements are accessed using zero-based indexing.
4. Efficient Memory Utilization: Memory is allocated contiguously, which improves
access time.
Applications of Arrays
• Storing and accessing data in fixed-size datasets (e.g., student grades, RGB pixel
values).
• Used in matrix operations, search algorithms, and sorting algorithms.

Types of Arrays
1. One-Dimensional Array
o Represents a linear list of elements.
o Example: A=[10,20,30,40,50]A = [10, 20, 30, 40, 50]A=[10,20,30,40,50]
2. Two-Dimensional Array
o Represents a table or matrix with rows and columns.
o Example: B=[123456789]B = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9
\end{bmatrix}B=147258369
3. Multi-Dimensional Array
o Arrays with more than two dimensions, used for complex data representation
like tensors in machine learning.
4. Dynamic Arrays
o Arrays that can grow or shrink in size, such as Python’s list.

Operations on Arrays
1. Insertion
o Adding an element to a specific position in the array.
o Example: Insert 15 at index 2.
Before: [10, 20, 30, 40]
After: [10, 20, 15, 30, 40]
2. Deletion
o Removing an element from a specific position.
o Example: Delete the element at index 3.
Before: [10, 20, 30, 40]
After: [10, 20, 30]
3. Traversal
o Accessing each element of the array sequentially.
o Example: Iterating through [10, 20, 30, 40].
4. Searching
o Finding the position of a given element.
o Example: Search for 30 in [10, 20, 30, 40] → Index: 2.
5. Sorting
o Arranging elements in ascending or descending order.
o Example: Sort [30, 10, 40, 20] → [10, 20, 30, 40].
6. Updating
o Modifying the value of an existing element.
o Example: Update the value at index 1 to 25.
Before: [10, 20, 30]
After: [10, 25, 30]

Arrays vs Lists
Feature Arrays Lists
Data Type Homogeneous (same type) Heterogeneous (mixed types allowed)
Size Fixed Dynamic (can grow/shrink)
Memory Usage Less (contiguous memory) More (due to overhead)
Performance Faster (efficient memory access) Slower (due to type checking)
Implementation Direct support (e.g., NumPy) Built-in Python list
Array Implementation in Python
Python doesn’t have a built-in array type like C or Java. Instead, it uses:
• array module: For homogeneous arrays.
• numpy library: For more advanced array operations.

Using the array Module


import array

# Create an array of integers


arr = array.array('i', [10, 20, 30, 40])

# Access elements
print(arr[0]) # Output: 10

# Insert element
arr.insert(2, 15) # Insert 15 at index 2
print(arr) # Output: array('i', [10, 20, 15, 30, 40])

# Remove element
arr.remove(30) # Remove the value 30
print(arr) # Output: array('i', [10, 20, 15, 40])

# Traverse
for element in arr:
print(element)

• Using the numpy Library

import numpy as np

# Create a 1D array
arr = np.array([10, 20, 30, 40])

# Access elements
print(arr[1]) # Output: 20
# Insert element (not in-place)
arr = np.insert(arr, 2, 15) # Insert 15 at index 2
print(arr) # Output: [10, 20, 15, 30, 40]

# Remove element (not in-place)


arr = np.delete(arr, 3) # Delete element at index 3
print(arr) # Output: [10, 20, 15, 40]

# Reshape into 2D array


arr_2d = arr.reshape(2, 2)
print(arr_2d)
# Output:
# [[10 20]
# [15 40]]

# Perform operations
print(np.sum(arr)) # Sum of elements
print(np.mean(arr)) # Mean of elements

Using the List (Full Implementation using class)

class Array:
def __init__(self):
"""Initialize an empty list to represent the array."""
self.data = []

def create(self, size, default_value=0):


"""Create an array of a specific size with a default value."""
if size < 0:
raise ValueError("Size must be non-negative")
self.data = [default_value] * size

def insert(self, index, value):


"""Insert an element at a specific index."""
if index < 0 or index > len(self.data):
raise IndexError("Index out of bounds")
self.data.insert(index, value)

def append(self, value):


"""Append an element to the end of the array."""
self.data.append(value)

def delete(self, index):


"""Delete an element at a specific index."""
if index < 0 or index >= len(self.data):
raise IndexError("Index out of bounds")
return self.data.pop(index)

def get(self, index):


"""Retrieve an element at a specific index."""
if index < 0 or index >= len(self.data):
raise IndexError("Index out of bounds")
return self.data[index]

def update(self, index, value):


"""Update the value of an element at a specific index."""
if index < 0 or index >= len(self.data):
raise IndexError("Index out of bounds")
self.data[index] = value

def search(self, value):


"""Search for the first occurrence of a value in the array."""
try:
return self.data.index(value)
except ValueError:
return -1 # Return -1 if the value is not found

def display(self):
"""Display all elements in the array."""
return self.data
def size(self):
"""Return the number of elements in the array."""
return len(self.data)

def clear(self):
"""Clear all elements in the array."""
self.data.clear()

def menu():
print("\n--- Array Operations Menu ---")
print("1. Create an array")
print("2. Append an element")
print("3. Insert an element")
print("4. Delete an element")
print("5. Get an element by index")
print("6. Update an element by index")
print("7. Search for an element")
print("8. Display the array")
print("9. Get the size of the array")
print("10. Clear the array")
print("0. Exit")
print("-----------------------------")

if __name__ == "__main__":
arr = Array()
while True:
menu()
choice = input("Enter your choice: ")
try:
if choice == "1":
size = int(input("Enter the size of the array: "))
default_value = int(input("Enter the default value
(default is 0): "))
arr.create(size, default_value)
print(f"Array of size {size} created with default value
{default_value}.")

elif choice == "2":


value = int(input("Enter the value to append: "))
arr.append(value)
print(f"{value} appended to the array.")

elif choice == "3":


index = int(input("Enter the index: "))
value = int(input("Enter the value: "))
arr.insert(index, value)
print(f"{value} inserted at index {index}.")

elif choice == "4":


index = int(input("Enter the index to delete: "))
deleted_value = arr.delete(index)
print(f"Deleted value: {deleted_value}")

elif choice == "5":


index = int(input("Enter the index to retrieve: "))
print(f"Element at index {index}: {arr.get(index)}")

elif choice == "6":


index = int(input("Enter the index to update: "))
value = int(input("Enter the new value: "))
arr.update(index, value)
print(f"Updated index {index} to value {value}.")

elif choice == "7":


value = int(input("Enter the value to search: "))
index = arr.search(value)
if index == -1:
print("Value not found.")
else:
print(f"Value found at index {index}.")

elif choice == "8":


print("Current array:", arr.display())

elif choice == "9":


print("Size of the array:", arr.size())

elif choice == "10":


arr.clear()
print("Array cleared.")

elif choice == "0":


print("Exiting program. Goodbye!")
break

else:
print("Invalid choice! Please try again.")
except Exception as e:
print(f"Error: {e}")

Output:

--- Array Operations Menu ---


1. Create an array
2. Append an element
3. Insert an element
4. Delete an element
5. Get an element by index
6. Update an element by index
7. Search for an element
8. Display the array
9. Get the size of the array
10. Clear the array
0. Exit
-----------------------------
Enter your choice: 1
Enter the size of the array: 5
Enter the default value (default is 0): 3
Array of size 5 created with default value 3.

Enter your choice: 8


Current array: [3, 3, 3, 3, 3]

2.2 Linked List


Linked List Overview
A linked list is a linear data structure where elements, called nodes, are connected using
pointers. Each node contains:
1. Data: The value or information.
2. Pointer (or Link): A reference to the next node in the sequence.
Unlike arrays, linked lists do not use contiguous memory. Instead, they dynamically allocate
memory, making them suitable for scenarios where the size of the dataset changes frequently.

Advantages of Linked Lists


• Dynamic Size: The size can grow or shrink as needed.
• Efficient Insertions/Deletions: Operations at the beginning or middle are faster than
arrays.
Disadvantages of Linked Lists
• Sequential Access: Random access is impossible, as traversal is required to reach a
specific node.
• Overhead: Additional memory is needed for pointers.

Types of Linked Lists


1. Singly Linked List
o Nodes are connected in one direction.
o Each node contains:
▪ Data.
▪ Pointer to the next node.
Example:

2. Doubly Linked List


o Nodes are connected in both directions.
o Each node contains:
▪ Data.
▪ Pointer to the next node.
▪ Pointer to the previous node.
Example:

3. Circular Linked List


o The last node points back to the first node, forming a circular structure.
o Can be singly or doubly linked.
Example:

Singly Linked List Implementation in Python


# Node class for a singly linked list
class Node:
def __init__(self, data):
self.data = data
self.next = None

# Linked List class


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

# Insert at the beginning


def insert_at_beginning(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node

# Insert at the end


def insert_at_end(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
return
temp = self.head
while temp.next:
temp = temp.next
temp.next = new_node

# Display the linked list


def display(self):
temp = self.head
while temp:
print(temp.data, end=" -> ")
temp = temp.next
print("None")

# Example usage
sll = SinglyLinkedList()
sll.insert_at_beginning(10)
sll.insert_at_end(20)
sll.insert_at_end(30)
sll.display() # Output: 10 -> 20 -> 30 -> None

Doubly Linked List Implementation in Python


# Node class for a doubly linked list
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None

# Doubly Linked List class


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

# Insert at the beginning


def insert_at_beginning(self, data):
new_node = Node(data)
new_node.next = self.head
if self.head:
self.head.prev = new_node
self.head = new_node

# Insert at the end


def insert_at_end(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
return
temp = self.head
while temp.next:
temp = temp.next
temp.next = new_node
new_node.prev = temp

# Display the linked list


def display(self):
temp = self.head
while temp:
print(temp.data, end=" <-> ")
temp = temp.next
print("None")

# Example usage
dll = DoublyLinkedList()
dll.insert_at_beginning(10)
dll.insert_at_end(20)
dll.insert_at_end(30)
dll.display() # Output: 10 <-> 20 <-> 30 <-> None

Circular Linked List Implementation in Python


# Node class for a circular linked list
class Node:
def __init__(self, data):
self.data = data
self.next = None

# Circular Linked List class


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

# Insert at the end


def insert_at_end(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
new_node.next = self.head
return
temp = self.head
while temp.next != self.head:
temp = temp.next
temp.next = new_node
new_node.next = self.head

# Display the circular linked list


def display(self):
if not self.head:
print("List is empty")
return
temp = self.head
while True:
print(temp.data, end=" -> ")
temp = temp.next
if temp == self.head:
break
print("(Back to Head)")

# Example usage
cll = CircularLinkedList()
cll.insert_at_end(10)
cll.insert_at_end(20)
cll.insert_at_end(30)
cll.display() # Output: 10 -> 20 -> 30 -> (Back to Head)

Comparison of Linked Lists


Feature Singly Linked Doubly Linked List Circular Linked List
List
Direction Single Double Single/Double
Memory Usage Less More (additional Like singly/doubly lists
pointer)
Complexity of Sequential Sequential, both Depends on
Traversal directions implementation
Use Case Simple data Backward and forward Cyclic data, round-robin
storage traversal scheduling
2.3 Stack
Overview of Stack
A stack is a linear data structure that adheres to the Last In, First Out (LIFO) principle. In this
structure, the last element added is the first to be removed. It is commonly compared to a
stack of plates where you can only add or remove the top plate.

Key Operations in Stack


1. Push: Add an element to the top of the stack.
2. Pop: Remove the top element from the stack.
3. Peek (or Top): View the top element without removing it.
4. IsEmpty: Check if the stack is empty.
5. Size: Get the number of elements in the stack.

Applications of Stack
1. Expression Evaluation and Conversion:
o Converting infix expressions to postfix or prefix.
o Evaluating postfix or prefix expressions.
2. Backtracking:
o Navigating undo operations in applications.
o Solving puzzles like mazes and the Tower of Hanoi.
3. Parenthesis Matching:
o Checking balanced parentheses in expressions.
4. Function Call Management:
o Maintaining function calls in recursion using the call stack.
5. Parsing and Compilers:
o Syntax checking during code compilation.

Implementation of Stack
Stacks can be implemented in various ways, such as using arrays, Python lists, or linked lists.

1. Implementation Using Python Lists


Python lists provide an easy way to implement a stack due to their built-in append() and pop()
methods.
class Stack:
def __init__(self):
"""Initialize an empty stack."""
self.stack = []

def push(self, value):


"""Push an element onto the stack."""
self.stack.append(value)

def pop(self):
"""Pop the top element from the stack."""
if self.is_empty():
raise IndexError("Stack underflow: Cannot pop from an
empty stack")
return self.stack.pop()

def peek(self):
"""Peek at the top element of the stack without removing it."""
if self.is_empty():
raise IndexError("Stack is empty: Cannot peek")
return self.stack[-1]

def is_empty(self):
"""Check if the stack is empty."""
return len(self.stack) == 0

def size(self):
"""Return the size of the stack."""
return len(self.stack)

def display(self):
"""Display all elements in the stack."""
if self.is_empty():
return "Stack is empty"
return self.stack[::-1] # Reverse order to show stack's top at
the beginning

def menu():
print("\n--- Stack Operations Menu ---")
print("1. Push an element")
print("2. Pop an element")
print("3. Peek at the top element")
print("4. Check if the stack is empty")
print("5. Get the size of the stack")
print("6. Display the stack")
print("0. Exit")
print("-----------------------------")

if __name__ == "__main__":
stack = Stack()
while True:
menu()
choice = input("Enter your choice: ")
try:
if choice == "1":
value = int(input("Enter the value to push: "))
stack.push(value)
print(f"{value} pushed onto the stack.")

elif choice == "2":


popped_value = stack.pop()
print(f"Popped value: {popped_value}")

elif choice == "3":


top_value = stack.peek()
print(f"Top value: {top_value}")

elif choice == "4":


if stack.is_empty():
print("The stack is empty.")
else:
print("The stack is not empty.")

elif choice == "5":


print(f"Size of the stack: {stack.size()}")

elif choice == "6":


print("Stack contents (top to bottom):", stack.display())

elif choice == "0":


print("Exiting program. Goodbye!")
break

else:
print("Invalid choice! Please try again.")
except Exception as e:
print(f"Error: {e}")

Output:

--- Stack Operations Menu ---


1. Push an element
2. Pop an element
3. Peek at the top element
4. Check if the stack is empty
5. Get the size of the stack
6. Display the stack
0. Exit
-----------------------------
Enter your choice: 1
Enter the value to push: 10
10 pushed onto the stack.

Enter your choice: 1


Enter the value to push: 20
20 pushed onto the stack.

Enter your choice: 6


Stack contents (top to bottom): [20, 10]

Enter your choice: 2


Popped value: 20

Enter your choice: 3


Top value: 10

Enter your choice: 0


Exiting program. Goodbye!

2. Implementation Using Linked Lists


This method is more memory-efficient, especially for dynamic data.
class Node:
def __init__(self, data):
self.data = data
self.next = None

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

def push(self, data):


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

def pop(self):
if self.is_empty():
return "Stack is empty"
popped_data = self.top.data
self.top = self.top.next
return popped_data

def peek(self):
if self.is_empty():
return "Stack is empty"
return self.top.data

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

def display(self):
temp = self.top
while temp:
print(temp.data, end=" -> ")
temp = temp.next
print("None")

# Example usage
s = Stack()
s.push(10)
s.push(20)
s.push(30)
print("Top Element:", s.peek()) # Output: Top Element: 30
s.pop()
s.display() # Output: 20 -> 10 -> None

Expression Evaluation Using Stack


Infix, Prefix, and Postfix Expressions
1. Infix Expression: Operators are placed between operands.
o Example: (A + B) * C
2. Postfix Expression: Operators come after operands.
o Example: A B + C *
3. Prefix Expression: Operators precede operands.
o Example: * + A B C

Steps to Evaluate a Postfix Expression


1. Scan the expression from left to right.
2. If an operand is encountered, push it onto the stack.
3. If an operator is encountered:
o Pop the top two elements from the stack.
o Perform the operation.
o Push the result back onto the stack.
4. At the end, the stack will contain the result.

Example: Evaluate Postfix Expression


Expression: 5 6 + 2 * 12 /
Steps:
1. Push 5, 6. Encounter +. Add 5 + 6 = 11. Push 11.
2. Push 2. Encounter *. Multiply 11 * 2 = 22. Push 22.
3. Push 12. Encounter /. Divide 22 / 12 = 1.833. Push 1.833.
Python Code:
python
Copy code
def evaluate_postfix(expression):
stack = []

for char in expression.split():


if char.isdigit():
stack.append(int(char))
else:
b = stack.pop()
a = stack.pop()
if char == '+':
stack.append(a + b)
elif char == '-':
stack.append(a - b)
elif char == '*':
stack.append(a * b)
elif char == '/':
stack.append(a / b)

return stack[0]

# Example usage
expression = "5 6 + 2 * 12 /"
result = evaluate_postfix(expression)
print("Result:", result) # Output: Result: 1.8333333333333333

Applications in Real Life


1. Undo Operations: Text editors use stacks to store undo commands.
2. Call Stack: Manages recursive function calls in programming.
3. Browser History: Maintains backtracking through pages.
Stacks are an essential data structure for efficient problem-solving in both academic and real-
world scenarios.

2.4 Queue

Overview of Queue
A queue is a linear data structure that follows the First In, First Out (FIFO) principle. In this
structure, the first element added is the first one to be removed, similar to a line of people
waiting for a service.
Key Operations in a Queue
1. Enqueue: Add an element to the rear of the queue.
2. Dequeue: Remove an element from the front of the queue.
3. Peek (or Front): View the front element without removing it.
4. IsEmpty: Check if the queue is empty.
5. Size: Get the number of elements in the queue.

Applications of Queues
1. Task Scheduling:
o Managing tasks in operating systems (CPU scheduling, Disk scheduling).
o Print job management in printers.
2. Customer Service Systems:
o Handling requests in call centers or help desks.
3. Data Transmission:
o Queuing packets in network routers.
4. Breadth-First Search (BFS):
o Used in graph traversal algorithms.
5. Simulation Problems:
o Traffic management or waiting line simulations.

Types of Queues
1. Simple Queue (Linear Queue):
o Follows FIFO.
o Operations are performed at two ends (enqueue at rear, dequeue at front).
2. Circular Queue:
o The last position is connected to the first, forming a circle.
o Avoids wastage of space in the array implementation of queues.
3. Priority Queue:
o Elements are dequeued based on priority, not on arrival order.
oUsed in tasks like Dijkstra's algorithm.
4. Double-Ended Queue (Deque):
o Insertion and deletion can be performed at both ends.
o Comes in two variants:
▪ Input-Restricted Deque: Insertions are restricted to one end.
▪ Output-Restricted Deque: Deletions are restricted to one end.

Implementation of Queue
Queues can be implemented using arrays, Python lists, or linked lists.

1. Implementation Using Python Lists


Python lists provide an easy way to implement a queue, though performance may degrade for
large datasets due to shifting elements during dequeue.
class Queue:
def __init__(self):
self.queue = []

def enqueue(self, item):


self.queue.append(item)

def dequeue(self):
if not self.is_empty():
return self.queue.pop(0)
else:
return "Queue is empty"

def peek(self):
if not self.is_empty():
return self.queue[0]
else:
return "Queue is empty"

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

def size(self):
return len(self.queue)

def display(self):
print(self.queue)

# Example usage
q = Queue()
q.enqueue(10)
q.enqueue(20)
q.enqueue(30)
print("Front Element:", q.peek()) # Output: Front Element: 10
q.dequeue()
q.display() # Output: [20, 30]

2. Implementation Using Linked Lists


Linked lists are more efficient for queue implementation as they avoid shifting
elements.
class Node:
def __init__(self, data):
self.data = data
self.next = None

class Queue:
def __init__(self):
self.front = None
self.rear = None

def enqueue(self, data):


new_node = Node(data)
if self.rear is None:
self.front = self.rear = new_node
return
self.rear.next = new_node
self.rear = new_node

def dequeue(self):
if self.front is None:
return "Queue is empty"
temp = self.front
self.front = temp.next
if self.front is None:
self.rear = None
return temp.data

def peek(self):
if self.front is None:
return "Queue is empty"
return self.front.data

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

def display(self):
temp = self.front
while temp:
print(temp.data, end=" -> ")
temp = temp.next
print("None")

# Example usage
q = Queue()
q.enqueue(10)
q.enqueue(20)
q.enqueue(30)
print("Front Element:", q.peek()) # Output: Front Element: 10
q.dequeue()
q.display() # Output: 20 -> 30 -> None

Circular Queue Implementation


class CircularQueue:
def __init__(self, size):
self.size = size
self.queue = [None] * size
self.front = self.rear = -1
def enqueue(self, data):
if (self.rear + 1) % self.size == self.front:
print("Queue is Full")
elif self.front == -1:
self.front = self.rear = 0
self.queue[self.rear] = data
else:
self.rear = (self.rear + 1) % self.size
self.queue[self.rear] = data

def dequeue(self):
if self.front == -1:
print("Queue is Empty")
elif self.front == self.rear:
temp = self.queue[self.front]
self.front = self.rear = -1
return temp
else:
temp = self.queue[self.front]
self.front = (self.front + 1) % self.size
return temp

def display(self):
if self.front == -1:
print("Queue is Empty")
elif self.rear >= self.front:
print(" ".join(map(str, self.queue[self.front : self.rear +
1])))
else:
print(" ".join(map(str, self.queue[self.front :] + self.queue[:
self.rear + 1])))

# Example usage
cq = CircularQueue(5)
cq.enqueue(10)
cq.enqueue(20)
cq.enqueue(30)
cq.display() # Output: 10 20 30
cq.dequeue()
cq.display() # Output: 20 30

Applications of Specific Queues


1. Simple Queue:
o Managing requests in servers.
o Ticketing systems.
2. Priority Queue:
o Emergency systems (high-priority patients are treated first).
o Pathfinding algorithms (e.g., A*).
3. Circular Queue:
o Buffer management in operating systems.
o Handling multimedia streams.
4. Deque:
o Browser history (back and forward navigation).
o Palindrome checking.
Queues are fundamental in many computational problems, particularly those
requiring efficient task scheduling and resource management.

Question Bank

Q.1…. 2 / 3.5 Marks Questions

Question Bloom's CO
Level Mapping
Define an array. Give an example of how arrays are Remembering CO1
used in real-life applications.
Explain the difference between a singly linked list and Understanding CO2
a doubly linked list.
What is the key principle of a stack? Illustrate with an Understanding CO2
example.
Describe the FIFO property of a queue with an Understanding CO3
example.
Write the syntax to declare an array in Python. Remembering CO1
Mention two advantages of using a circular queue over Understanding CO3
a simple queue.
What is the primary use of a priority queue? Understanding CO4
Compare the time complexities of stack operations: Analyzing CO2
Push and Pop.

3.5-Marks Questions

Question Bloom's CO
Level Mapping
Implement a Python program to find the maximum Applying CO1
element in an array.
Illustrate with code how to insert a node into a singly Applying CO2
linked list.
Explain with examples the real-life applications of stacks Analyzing CO2
in expression evaluation.
Write a Python function to check if a queue is empty or Applying CO3
full in a circular queue.
Compare arrays and linked lists in terms of memory usage Analyzing CO1, CO2
and performance.
Design a priority queue to store tasks with different Creating CO4
urgency levels and explain how tasks are dequeued.
Explain with code how to reverse a stack using recursion. Applying CO2
Analyze the differences between deque and a circular Analyzing CO3, CO4
queue with examples.

Q.2…. 5 / 7 Marks Questions

Question Bloom's CO
Level Mapping
Write a Python program to merge two arrays and sort the Applying CO1
resulting array in ascending order.
Explain with an example how to delete a node from the Applying CO2
middle of a singly linked list.
Discuss the process of evaluating a postfix expression Analyzing CO2
using a stack. Provide an example.
Write a Python function to implement a circular queue Applying CO3
with enqueue and dequeue operations.
Compare stacks and queues in terms of their Analyzing CO2, CO3
applications and data handling techniques.
Explain the concept of dynamic memory allocation and Understanding CO2
how it is utilized in linked lists.
Describe in detail the real-world applications of queues, Understanding CO3, CO4
giving examples for at least two types of queues.

7-Marks Questions
Design and implement a Python program to reverse an array without Creating CO1
using an additional array.
Write a Python function to perform the following operations on a Creating CO2
doubly linked list: insert at the beginning, delete from the end, and
display the list.
Discuss how recursion can be used to implement a stack and write a Creating CO2
Python program for the same.
Explain the concept of circular queues with the help of an example. Applying CO3
Write a Python program to demonstrate the enqueue and dequeue
operations in a circular queue.
Analyze the advantages and disadvantages of arrays and linked lists. Evaluating CO1,
Which data structure is better for dynamic data, and why? CO2
Design a priority queue for a hospital system where patients are Creating CO4
treated based on urgency. Explain the algorithm and implement it in
Python.
Compare and contrast the use of stacks and queues in solving real- Evaluating CO2,
world problems, providing examples for both. CO3

Q.3…. 14 Marks Questions

Question Bloom's CO
Level Mapping
Design and implement a Python program to create a menu-driven Creating CO1
system for array operations, including insertion, deletion, searching,
and sorting. Explain the logic behind each operation.
Write a Python program to implement a doubly linked list with the Creating CO2
following operations: insertion at the beginning, insertion at a specific
position, deletion from the end, and displaying the list in reverse order.
Discuss the time complexity of each operation.
Discuss the concept of stack-based expression evaluation. Write a Creating, CO2
Python program to evaluate an infix expression by converting it into a Analyzing
postfix expression and then evaluating it using a stack. Provide an
example and step-by-step explanation.
Compare and contrast the different types of queues (simple queue, Analyzing, CO3,
circular queue, and priority queue) in terms of their functionality, use Creating CO4
cases, and implementation complexities. Write Python code to
demonstrate the operations of a priority queue.
Analyze and implement a Python program to manage a print queue Evaluating, CO3,
system using a circular queue, where tasks are prioritized based on Creating CO4
arrival time and priority. Discuss the challenges in designing such a
system.
Describe in detail the memory management techniques used in linked Understand CO2
lists compared to arrays. Implement a Python program to create a ing,
linked list that supports dynamic memory allocation for insertion and Creating
deletion at any position.
Design a Python-based library management system that uses stacks Creating, CO3,
and queues for book borrowing and returning. Provide a detailed Evaluating CO4
explanation of the data structures used and the logic behind each
operation.

You might also like