0% found this document useful (0 votes)
16 views39 pages

R23 DS Using Python ECE

The document outlines various Python programming exercises focused on data structures, including the creation of a Flower class, an inheritance hierarchy for polygons, method overloading and overriding, and comprehensions (list, dictionary, and set). Each section provides example code and expected output for clarity. The exercises aim to enhance understanding of object-oriented programming and Python's data handling capabilities.

Uploaded by

bslsdevi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views39 pages

R23 DS Using Python ECE

The document outlines various Python programming exercises focused on data structures, including the creation of a Flower class, an inheritance hierarchy for polygons, method overloading and overriding, and comprehensions (list, dictionary, and set). Each section provides example code and expected output for clarity. The exercises aim to enhance understanding of object-oriented programming and Python's data handling capabilities.

Uploaded by

bslsdevi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 39

DATA STRUCTURES USING PYTHON

List of Experiments:

1. Write a Python program for class, Flower, that has three instance variables of type str,

int, and float that respectively represent the name of the flower, its number of petals,

and its price. Your class must include a constructor method that initializes each

variable to an appropriate value, and your class should include methods for setting the

value of each type, and retrieving the value of each type.

Program:

class Flower:

def __init__(self, name: str, petals: int, price: float):

"""Constructor to initialize the flower's name, number of petals, and price."""

self._name = name

self._petals = petals

self._price = price

# Getter methods

def get_name(self) -> str:

"""Returns the name of the flower."""

return self._name

def get_petals(self) -> int:

"""Returns the number of petals."""

return self._petals

def get_price(self) -> float:

"""Returns the price of the flower."""

return self._price

# Setter methods

def set_name(self, name: str):

"""Sets the name of the flower."""

self._name = name

def set_petals(self, petals: int):

"""Sets the number of petals."""

self._petals = petals

def set_price(self, price: float):


"""Sets the price of the flower."""

self._price = price

# Example usage:

flower = Flower("Rose", 32, 2.5)

# Accessing values using getter methods

print(f"Name: {flower.get_name()}")

print(f"Petals: {flower.get_petals()}")

print(f"Price: {flower.get_price()}")

# Modifying values using setter methods

flower.set_name("Tulip")

flower.set_petals(25)

flower.set_price(3.0)

# Accessing updated values

print(f"Updated Name: {flower.get_name()}")

print(f"Updated Petals: {flower.get_petals()}")

print(f"Updated Price: {flower.get_price()}")

Output:

Name: Rose

Petals: 32

Price: 2.5

Updated Name: Tulip

Updated Petals: 25

Updated Price: 3.0

2. Develop an inheritance hierarchy based upon a Polygon class that has abstract

methods area( ) and perimeter( ). Implement classes Triangle, Quadrilateral,

Pentagon, that extend this base class, with the obvious meanings for the area( ) and

perimeter( ) methods. Write a simple program that allows users to create polygons of

the various types and input their geometric dimensions, and the program then outputs

their area and perimeter

Program:

from abc import ABC, abstractmethod

import math
# Base Polygon class with abstract methods

class Polygon(ABC):

@abstractmethod

def area(self):

"""Calculate the area of the polygon."""

pass

@abstractmethod

def perimeter(self):

"""Calculate the perimeter of the polygon."""

pass

# Triangle class extending Polygon

class Triangle(Polygon):

def __init__(self, a: float, b: float, c: float, height: float):

self.a = a

self.b = b

self.c = c

self.height = height

def area(self):

"""Area of a triangle = 0.5 * base * height"""

return 0.5 * self.a * self.height

def perimeter(self):

"""Perimeter of a triangle = sum of all sides"""

return self.a + self.b + self.c

# Quadrilateral class extending Polygon

class Quadrilateral(Polygon):

def __init__(self, a: float, b: float, c: float, d: float, height: float):

self.a = a

self.b = b

self.c = c

self.d = d

self.height = height
def area(self):

"""Area of a simple quadrilateral can be calculated with base * height"""

return self.a * self.height

def perimeter(self):

"""Perimeter of a quadrilateral = sum of all sides"""

return self.a + self.b + self.c + self.d

# Pentagon class extending Polygon

class Pentagon(Polygon):

def __init__(self, side: float):

self.side = side

def area(self):

"""Area of a regular pentagon = (sqrt(5(5 + 2sqrt(5))) * side^2) / 4"""

return (math.sqrt(5 * (5 + 2 * math.sqrt(5))) * self.side ** 2) / 4

def perimeter(self):

"""Perimeter of a regular pentagon = 5 * side"""

return 5 * self.side

# Function to create polygon and display area and perimeter

def create_polygon():

print("Choose a polygon:")

print("1. Triangle")

print("2. Quadrilateral")

print("3. Pentagon")

choice = int(input("Enter the number of the polygon type: "))

if choice == 1:

a = float(input("Enter side a of the triangle: "))

b = float(input("Enter side b of the triangle: "))

c = float(input("Enter side c of the triangle: "))

height = float(input(f"Enter the height corresponding to side a: "))

triangle = Triangle(a, b, c, height)

print(f"Triangle Area: {triangle.area():.2f}")

print(f"Triangle Perimeter: {triangle.perimeter():.2f}")

elif choice == 2:
a = float(input("Enter side a of the quadrilateral: "))

b = float(input("Enter side b of the quadrilateral: "))

c = float(input("Enter side c of the quadrilateral: "))

d = float(input("Enter side d of the quadrilateral: "))

height = float(input(f"Enter the height corresponding to side a: "))

quadrilateral = Quadrilateral(a, b, c, d, height)

print(f"Quadrilateral Area: {quadrilateral.area():.2f}")

print(f"Quadrilateral Perimeter: {quadrilateral.perimeter():.2f}")

elif choice == 3:

side = float(input("Enter the side length of the pentagon: "))

pentagon = Pentagon(side)

print(f"Pentagon Area: {pentagon.area():.2f}")

print(f"Pentagon Perimeter: {pentagon.perimeter():.2f}")

else:

print("Invalid choice.")

# Run the program

if __name__ == "__main__":

create_polygon()

Output:

Choose a polygon:

1. Triangle

2. Quadrilateral

3. Pentagon

Enter the number of the polygon type: 3

Enter the side length of the pentagon: 5

Pentagon Area: 43.01

Pentagon Perimeter: 25.00

Choose a polygon:

1. Triangle

2. Quadrilateral

3. Pentagon
Enter the number of the polygon type: 1

Enter side a of the triangle: 3

Enter side b of the triangle: 4

Enter side c of the triangle: 5

Enter the height corresponding to side a: 2

Triangle Area: 3.00

Triangle Perimeter: 12.00

3. Write a python program to implement Method Overloading and Method Overriding.

Program:

# Method Overloading simulation using default arguments

class Calculator:

def add(self, a=None, b=None, c=None):

"""Simulate method overloading by using default arguments."""

if a is not None and b is not None and c is not None:

return a + b + c # If three arguments are provided

elif a is not None and b is not None:

return a + b # If two arguments are provided

elif a is not None:

return a # If only one argument is provided

else:

return 0 # If no arguments are provided

# Method Overriding example

class Animal:

def sound(self):

"""Base class method."""

print("This animal makes a sound.")

class Dog(Animal):

def sound(self):

"""Overriding the base class method."""

print("The dog barks.")


class Cat(Animal):

def sound(self):

"""Overriding the base class method."""

print("The cat meows.")

# Testing Method Overloading

calc = Calculator()

# Different usages of the overloaded 'add' method

print(f"Sum (one arg): {calc.add(10)}") # Only one argument

print(f"Sum (two args): {calc.add(10, 20)}") # Two arguments

print(f"Sum (three args): {calc.add(10, 20, 30)}") # Three arguments

# Testing Method Overriding

dog = Dog()

cat = Cat()

# Each subclass overrides the 'sound' method of the Animal class

dog.sound() # The dog barks

cat.sound() # The cat meows

Output:

Sum (one arg): 10

Sum (two args): 30

Sum (three args): 60

The dog barks.

The cat meows.

4. Write a Python program to illustrate the following comprehensions:

a) List Comprehensions

Program:

input_list = [1, 2, 3, 4, 4, 5, 6, 7, 7]
output_list = []
for var in input_list:
if var % 2 == 0:
output_list.append(var)

print("Output List using for loop:", output_list)


Output:

Output List using for loop: [2, 4, 4, 6]

# Example 1: Create a list of squares of numbers from 1 to 10

squares = [x**2 for x in range(1, 11)]

print(f"Squares of numbers from 1 to 10: {squares}")

Output:

Squares of numbers from 1 to 10: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# Example 2: Create a list of even numbers from 1 to 20

evens = [x for x in range(1, 21) if x % 2 == 0]

print(f"Even numbers from 1 to 20: {evens}")

Output:

Even numbers from 1 to 20: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

# Example 3: Create a list of the first letters of each word in a list

words = ["apple", "banana", "cherry", "date"]

first_letters = [word[0] for word in words]

print(f"First letters of each word: {first_letters}")

Output:

First letters of each word: ['a', 'b', 'c', 'd']

# Example 4: Create a list of numbers divisible by both 3 and 5 from 1 to 50

divisible_by_3_and_5 = [x for x in range(1, 51) if x % 3 == 0 and x % 5 == 0]

print(f"Numbers divisible by 3 and 5 from 1 to 50: {divisible_by_3_and_5}")

Output:

Numbers divisible by 3 and 5 from 1 to 50: [15, 30, 45]

# Example 5: Convert a list of strings to uppercase

fruits = ["apple", "banana", "cherry"]

uppercase_fruits = [fruit.upper() for fruit in fruits]

print(f"Fruits in uppercase: {uppercase_fruits}")

Output:
Fruits in uppercase: ['APPLE', 'BANANA', 'CHERRY']

# Example 6: Create a list of tuples where each tuple contains a number and its square

num_square_tuples = [(x, x**2) for x in range(1, 6)]

print(f"List of tuples (number, square): {num_square_tuples}")

Output:

List of tuples (number, square): [(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]

# Example 7: Flatten a 2D matrix into a single list

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

flattened_matrix = [element for row in matrix for element in row]

print(f"Flattened matrix: {flattened_matrix}")

Output:

Flattened matrix: [1, 2, 3, 4, 5, 6, 7, 8, 9]

b) Dictionary Comprehensions

# Example 1: Create a dictionary where keys are numbers and values are their squares

squares_dict = {x: x**2 for x in range(1, 6)}

print(f"Squares dictionary: {squares_dict}")

Output

Squares dictionary: {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Example 2: Create a dictionary from two lists of the same length (keys and values)

keys = ['name', 'age', 'city']

values = ['Alice', 25, 'New York']

person_dict = {keys[i]: values[i] for i in range(len(keys))}

print(f"Dictionary from lists: {person_dict}")

Output:

Dictionary from lists: {'name': 'Alice', 'age': 25, 'city': 'New York'}

# Example 3: Create a dictionary of numbers and their cubes, but only for even numbers
even_cubes_dict = {x: x**3 for x in range(1, 11) if x % 2 == 0}

print(f"Even cubes dictionary: {even_cubes_dict}")

Output:

Even cubes dictionary: {2: 8, 4: 64, 6: 216, 8: 512, 10: 1000}

# Example 4: Convert a list of tuples (key, value) into a dictionary

tuple_list = [('apple', 3), ('banana', 5), ('cherry', 7)]

fruit_dict = {key: value for (key, value) in tuple_list}

print(f"Dictionary from tuple list: {fruit_dict}")

Output:

Dictionary from tuple list: {'apple': 3, 'banana': 5, 'cherry': 7}

# Example 5: Swap the keys and values in a given dictionary

original_dict = {'a': 1, 'b': 2, 'c': 3}

swapped_dict = {value: key for key, value in original_dict.items()}

print(f"Swapped dictionary (keys and values swapped): {swapped_dict}")

Output:

Swapped dictionary (keys and values swapped): {1: 'a', 2: 'b', 3: 'c'}

# Example 6: Create a dictionary with only items from an existing dictionary where the value is greater than 1

filtered_dict = {key: value for key, value in original_dict.items() if value > 1}

print(f"Filtered dictionary (values > 1): {filtered_dict}")

Output:

Filtered dictionary (values > 1): {'b': 2, 'c': 3}

c) Set Comprehensions

# Example 1: Create a set of squares of numbers from 1 to 10

squares_set = {x**2 for x in range(1, 11)}

print(f"Set of squares from 1 to 10: {squares_set}")

Output:

Set of squares from 1 to 10: {64, 1, 4, 36, 100, 9, 16, 49, 81, 25}
# Example 2: Create a set of even numbers from 1 to 20

evens_set = {x for x in range(1, 21) if x % 2 == 0}

print(f"Set of even numbers from 1 to 20: {evens_set}")

Output:

Set of even numbers from 1 to 20: {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}

# Example 3: Create a set of unique characters from a string (excluding spaces)

string = "hello world"

unique_chars = {char for char in string if char != ' '}

print(f"Set of unique characters from the string: {unique_chars}")

Output:

Set of unique characters from the string: {'r', 'd', 'e', 'o', 'l', 'h', 'w'}

# Example 4: Create a set of numbers divisible by 3 or 5 from 1 to 30

divisible_by_3_or_5 = {x for x in range(1, 31) if x % 3 == 0 or x % 5 == 0}

print(f"Set of numbers divisible by 3 or 5 from 1 to 30: {divisible_by_3_or_5}")

Output:

Set of numbers divisible by 3 or 5 from 1 to 30: {3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30}

# Example 5: Convert a list of words to lowercase and remove duplicates using a set comprehension

words = ["Apple", "Banana", "Cherry", "apple", "banana", "CHERRY"]

lowercase_words = {word.lower() for word in words}

print(f"Set of lowercase words: {lowercase_words}")

Output:

Set of lowercase words: {'apple', 'cherry', 'banana'}

# Example 6: Create a set of cubes of odd numbers from 1 to 10

odd_cubes_set = {x**3 for x in range(1, 11) if x % 2 != 0}

print(f"Set of cubes of odd numbers from 1 to 10: {odd_cubes_set}")

Output:

Set of cubes of odd numbers from 1 to 10: {1, 343, 729, 27, 125}
d) Generator Comprehensions

# Example 1: Generator for squares of numbers from 1 to 10

squares_generator = (x**2 for x in range(1, 11))

print("Squares of numbers from 1 to 10:")

for square in squares_generator:

print(square)

Output:

Squares of numbers from 1 to 10:

16

25

36

49

64

81

100

# Example 2: Generator for even numbers from 1 to 20

evens_generator = (x for x in range(1, 21) if x % 2 == 0)

print("\nEven numbers from 1 to 20:")

for even in evens_generator:

print(even)

Output:

Even numbers from 1 to 20:

10
12

14

16

18

20

# Example 3: Generator for unique characters in a string (excluding spaces)

string = "hello world"

unique_chars_generator = (char for char in string if char != ' ')

print("\nUnique characters in the string 'hello world':")

for char in unique_chars_generator:

print(char)

Output:

Unique characters in the string 'hello world':

# Example 4: Generator for numbers divisible by 3 or 5 from 1 to 30

divisible_by_3_or_5_generator = (x for x in range(1, 31) if x % 3 == 0 or x % 5 == 0)

print("\nNumbers divisible by 3 or 5 from 1 to 30:")

for number in divisible_by_3_or_5_generator:

print(number)

Output:

Numbers divisible by 3 or 5 from 1 to 30:


3

10

12

15

18

20

21

24

25

27

30

# Example 5: Generator for cubes of odd numbers from 1 to 10

odd_cubes_generator = (x**3 for x in range(1, 11) if x % 2 != 0)

print("\nCubes of odd numbers from 1 to 10:")

for cube in odd_cubes_generator:

print(cube)

Output:

Cubes of odd numbers from 1 to 10:

27

125

343

729

5. Write a Python program to generate the combinations of n distinct objects taken from the elements of a
given list. Example: Original list: [1, 2, 3, 4, 5, 6, 7, 8, 9] Combinations of 2 distinct objects: [1, 2] [1, 3] [1, 4]
[1, 5] .... [7, 8] [7, 9] [8, 9].

Program:

import itertools
# Define the original list

original_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]

# Number of distinct objects to choose (in this case, 2)

n=2

# Generate combinations of n distinct objects

combinations = itertools.combinations(original_list, n)

# Print the combinations

print(f"Combinations of {n} distinct objects from the list:")

for combination in combinations:

print(combination)

Output:

Combinations of 2 distinct objects from the list:

(1, 2)

(1, 3)

(1, 4)

(1, 5)

(1, 6)

(1, 7)

(1, 8)

(1, 9)

(2, 3)

(2, 4)

(2, 5)

(2, 6)

(2, 7)

(2, 8)

(2, 9)

(3, 4)

(3, 5)

(3, 6)
(3, 7)

(3, 8)

(3, 9)

(4, 5)

(4, 6)

(4, 7)

(4, 8)

(4, 9)

(5, 6)

(5, 7)

(5, 8)

(5, 9)

(6, 7)

(6, 8)

(6, 9)

(7, 8)

(7, 9)

(8, 9)

6. Write a program for Linear Search and Binary search.

Program:

def linear_search(arr, target):

"""Perform a linear search on the array."""

for index, value in enumerate(arr):

if value == target:

return index # Return the index where the target is found

return -1 # Return -1 if the target is not found

def binary_search(arr, target):

"""Perform a binary search on the sorted array."""

left, right = 0, len(arr) - 1

while left <= right:

mid = left + (right - left) // 2 # Find the middle index


if arr[mid] == target:

return mid # Return the index if the target is found

elif arr[mid] < target:

left = mid + 1 # Adjust the left boundary

else:

right = mid - 1 # Adjust the right boundary

return -1 # Return -1 if the target is not found

# Test the search functions

if __name__ == "__main__":

# Sample data

numbers = [4, 2, 7, 1, 3, 5, 6]

sorted_numbers = sorted(numbers) # Sort the list for binary search

target = 3

# Linear Search

print("Linear Search:")

result = linear_search(numbers, target)

if result != -1:

print(f"Target {target} found at index: {result}")

else:

print(f"Target {target} not found.")

# Binary Search

print("\nBinary Search:")

result = binary_search(sorted_numbers, target)

if result != -1:

print(f"Target {target} found at index: {result} in the sorted array.")

else:

print(f"Target {target} not found in the sorted array.")

Output:

Linear Search:

Target 3 found at index: 4

Binary Search:

Target 3 found at index: 2 in the sorted array.


7. Write a program to implement Bubble Sort and Selection Sort.

Program:

def bubble_sort(arr):

"""Perform Bubble Sort on the given array."""

n = len(arr)

for i in range(n):

# Track if any swapping occurs

swapped = False

for j in range(0, n - i - 1):

if arr[j] > arr[j + 1]: # Compare adjacent elements

arr[j], arr[j + 1] = arr[j + 1], arr[j] # Swap if out of order

swapped = True

if not swapped: # No swaps means the array is sorted

break

return arr

def selection_sort(arr):

"""Perform Selection Sort on the given array."""

n = len(arr)

for i in range(n):

min_index = i # Assume the minimum is the first element

for j in range(i + 1, n):

if arr[j] < arr[min_index]: # Find the minimum element

min_index = j

# Swap the found minimum element with the first element

arr[i], arr[min_index] = arr[min_index], arr[i]

return arr

# Test the sorting functions

if __name__ == "__main__":

# Sample data

numbers = [64, 34, 25, 12, 22, 11, 90]

# Bubble Sort
print("Original list:", numbers)

sorted_numbers_bubble = bubble_sort(numbers.copy()) # Use copy to retain original list

print("Sorted list using Bubble Sort:", sorted_numbers_bubble)

# Selection Sort

sorted_numbers_selection = selection_sort(numbers.copy()) # Use copy to retain original list

print("Sorted list using Selection Sort:", sorted_numbers_selection)

Output:

Original list: [64, 34, 25, 12, 22, 11, 90]

Sorted list using Bubble Sort: [11, 12, 22, 25, 34, 64, 90]

Sorted list using Selection Sort: [11, 12, 22, 25, 34, 64, 90]

8. Write a program to implement Merge sort and Quick sort.

Program:

def merge_sort(arr):

"""Perform Merge Sort on the given array."""

if len(arr) > 1:

mid = len(arr) // 2 # Find the middle of the array

left_half = arr[:mid] # Divide the array elements into 2 halves

right_half = arr[mid:]

merge_sort(left_half) # Sort the first half

merge_sort(right_half) # Sort the second half

i = j = k = 0 # Initialize index variables

# Copy data to temp arrays L[] and R[]

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

# Checking if any element was left


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

return arr

def quick_sort(arr):

"""Perform Quick Sort on the given array."""

if len(arr) <= 1: # Base case for recursion

return arr

else:

pivot = arr[len(arr) // 2] # Choosing the middle element as the pivot

left = [x for x in arr if x < pivot] # Elements less than the pivot

middle = [x for x in arr if x == pivot] # Elements equal to the pivot

right = [x for x in arr if x > pivot] # Elements greater than the pivot

return quick_sort(left) + middle + quick_sort(right) # Recursive sorting

# Test the sorting functions

if __name__ == "__main__":

# Sample data

numbers = [64, 34, 25, 12, 22, 11, 90]

# Merge Sort

print("Original list:", numbers)

sorted_numbers_merge = merge_sort(numbers.copy()) # Use copy to retain original list

print("Sorted list using Merge Sort:", sorted_numbers_merge)

# Quick Sort

sorted_numbers_quick = quick_sort(numbers.copy()) # Use copy to retain original list

print("Sorted list using Quick Sort:", sorted_numbers_quick)

Output:

Original list: [64, 34, 25, 12, 22, 11, 90]


Sorted list using Merge Sort: [11, 12, 22, 25, 34, 64, 90]

Sorted list using Quick Sort: [11, 12, 22, 25, 34, 64, 90]

9. Write a program to implement Stacks and Queues.

Program:

class Stack:

"""A simple implementation of a Stack."""

def __init__(self):

self.items = [] # Initialize an empty list to store stack elements

def push(self, item):

"""Push an item onto the stack."""

self.items.append(item)

print(f"Pushed {item} onto the stack.")

def pop(self):

"""Pop an item off the stack."""

if not self.is_empty():

popped_item = self.items.pop()

print(f"Popped {popped_item} from the stack.")

return popped_item

else:

print("Stack is empty. Cannot pop.")

return None

def peek(self):

"""Return the top item of the stack without removing it."""

if not self.is_empty():

return self.items[-1]

else:

print("Stack is empty. Nothing to peek.")

return None

def is_empty(self):

"""Check if the stack is empty."""

return len(self.items) == 0
def size(self):

"""Return the size of the stack."""

return len(self.items)

class Queue:

"""A simple implementation of a Queue."""

def __init__(self):

self.items = [] # Initialize an empty list to store queue elements

def enqueue(self, item):

"""Add an item to the end of the queue."""

self.items.append(item)

print(f"Enqueued {item} into the queue.")

def dequeue(self):

"""Remove and return the front item from the queue."""

if not self.is_empty():

dequeued_item = self.items.pop(0)

print(f"Dequeued {dequeued_item} from the queue.")

return dequeued_item

else:

print("Queue is empty. Cannot dequeue.")

return None

def front(self):

"""Return the front item of the queue without removing it."""

if not self.is_empty():

return self.items[0]

else:

print("Queue is empty. Nothing at the front.")

return None

def is_empty(self):

"""Check if the queue is empty."""

return len(self.items) == 0

def size(self):
"""Return the size of the queue."""

return len(self.items)

# Test the Stack and Queue implementations

if __name__ == "__main__":

# Stack operations

print("Stack Operations:")

stack = Stack()

stack.push(10)

stack.push(20)

stack.push(30)

print(f"Top item is: {stack.peek()}")

stack.pop()

print(f"Stack size is: {stack.size()}")

stack.pop()

stack.pop()

stack.pop() # Attempt to pop from an empty stack

# Queue operations

print("\nQueue Operations:")

queue = Queue()

queue.enqueue(1)

queue.enqueue(2)

queue.enqueue(3)

print(f"Front item is: {queue.front()}")

queue.dequeue()

print(f"Queue size is: {queue.size()}")

queue.dequeue()

queue.dequeue()

queue.dequeue() # Attempt to dequeue from an empty queue

Output:

Stack Operations:

Pushed 10 onto the stack.

Pushed 20 onto the stack.


Pushed 30 onto the stack.

Top item is: 30

Popped 30 from the stack.

Stack size is: 2

Popped 20 from the stack.

Popped 10 from the stack.

Stack is empty. Cannot pop.

Queue Operations:

Enqueued 1 into the queue.

Enqueued 2 into the queue.

Enqueued 3 into the queue.

Front item is: 1

Dequeued 1 from the queue.

Queue size is: 2

Dequeued 2 from the queue.

Dequeued 3 from the queue.

Queue is empty. Cannot dequeue.

10. Write a program to implement Singly Linked List.

Program:

class Node:

"""A Node of a Singly Linked List."""

def __init__(self, data):

self.data = data # Store the data

self.next = None # Pointer to the next node

class SinglyLinkedList:

"""A Singly Linked List."""

def __init__(self):

self.head = None # Initialize the head of the list

def append(self, data):

"""Add a new node at the end of the list."""

new_node = Node(data)
if not self.head:

self.head = new_node # If the list is empty, set head to the new node

print(f"Appended {data} as the head node.")

return

last_node = self.head

while last_node.next: # Traverse to the last node

last_node = last_node.next

last_node.next = new_node # Link the last node to the new node

print(f"Appended {data} to the list.")

def delete(self, key):

"""Delete the first occurrence of a node with the given key."""

current = self.head

previous = None

# If the head node itself holds the key to be deleted

if current and current.data == key:

self.head = current.next # Change head

print(f"Deleted {key} from the list.")

return

# Search for the key to be deleted

while current and current.data != key:

previous = current

current = current.next

# If key was not present in the list

if not current:

print(f"{key} not found in the list.")

return

# Unlink the node from the list

previous.next = current.next

print(f"Deleted {key} from the list.")

def search(self, key):

"""Search for a node with the given key."""

current = self.head
while current:

if current.data == key:

print(f"{key} found in the list.")

return True

current = current.next

print(f"{key} not found in the list.")

return False

def display(self):

"""Display the entire list."""

current = self.head

if not current:

print("The list is empty.")

return

print("Singly Linked List:")

while current:

print(f"{current.data} -> ", end="")

current = current.next

print("None") # Indicate the end of the list

# Test the Singly Linked List implementation

if __name__ == "__main__":

linked_list = SinglyLinkedList()

# Append nodes

linked_list.append(10)

linked_list.append(20)

linked_list.append(30)

# Display the list

linked_list.display()

# Search for a node

linked_list.search(20)

linked_list.search(40)

# Delete a node

linked_list.delete(20)
linked_list.display()

# Attempt to delete a node that does not exist

linked_list.delete(40)

# Display the final state of the list

linked_list.display()

Output:

Appended 10 as the head node.

Appended 20 to the list.

Appended 30 to the list.

Singly Linked List:

10 -> 20 -> 30 -> None

20 found in the list.

40 not found in the list.

Deleted 20 from the list.

Singly Linked List:

10 -> 30 -> None

40 not found in the list.

Singly Linked List:

10 -> 30 -> None

11. Write a program to implement Doubly Linked list.

Program:

class Node:

"""A Node of a Doubly Linked List."""

def __init__(self, data):

self.data = data # Store the data

self.next = None # Pointer to the next node

self.prev = None # Pointer to the previous node

class DoublyLinkedList:

"""A Doubly Linked List."""

def __init__(self):
self.head = None # Initialize the head of the list

def append(self, data):

"""Add a new node at the end of the list."""

new_node = Node(data)

if not self.head:

self.head = new_node # If the list is empty, set head to the new node

print(f"Appended {data} as the head node.")

return

last_node = self.head

while last_node.next: # Traverse to the last node

last_node = last_node.next

last_node.next = new_node # Link the last node to the new node

new_node.prev = last_node # Link the new node back to the last node

print(f"Appended {data} to the list.")

def delete(self, key):

"""Delete the first occurrence of a node with the given key."""

current = self.head

# If the head node itself holds the key to be deleted

if current and current.data == key:

self.head = current.next # Change head

if self.head: # If there's a new head, set its prev to None

self.head.prev = None

print(f"Deleted {key} from the list.")

return

# Search for the key to be deleted

while current and current.data != key:

current = current.next

# If key was not present in the list

if not current:

print(f"{key} not found in the list.")

return

# Unlink the node from the list


if current.next: # If the node to be deleted is not the last node

current.next.prev = current.prev

if current.prev: # If the node to be deleted is not the first node

current.prev.next = current.next

print(f"Deleted {key} from the list.")

def search(self, key):

"""Search for a node with the given key."""

current = self.head

while current:

if current.data == key:

print(f"{key} found in the list.")

return True

current = current.next

print(f"{key} not found in the list.")

return False

def display_forward(self):

"""Display the entire list in forward direction."""

current = self.head

if not current:

print("The list is empty.")

return

print("Doubly Linked List (Forward):")

while current:

print(f"{current.data} <-> ", end="")

current = current.next

print("None") # Indicate the end of the list

def display_backward(self):

"""Display the entire list in backward direction."""

current = self.head

if not current:

print("The list is empty.")

return
# Move to the last node

while current.next:

current = current.next

print("Doubly Linked List (Backward):")

while current:

print(f"{current.data} <-> ", end="")

current = current.prev

print("None") # Indicate the start of the list

# Test the Doubly Linked List implementation

if __name__ == "__main__":

doubly_linked_list = DoublyLinkedList()

# Append nodes

doubly_linked_list.append(10)

doubly_linked_list.append(20)

doubly_linked_list.append(30)

# Display the list forward and backward

doubly_linked_list.display_forward()

doubly_linked_list.display_backward()

# Search for a node

doubly_linked_list.search(20)

doubly_linked_list.search(40)

# Delete a node

doubly_linked_list.delete(20)

doubly_linked_list.display_forward()

doubly_linked_list.display_backward()

# Attempt to delete a node that does not exist

doubly_linked_list.delete(40)

# Display the final state of the list

doubly_linked_list.display_forward()

doubly_linked_list.display_backward()
Output:

Appended 10 as the head node.

Appended 20 to the list.

Appended 30 to the list.

Doubly Linked List (Forward):

10 <-> 20 <-> 30 <-> None

Doubly Linked List (Backward):

30 <-> 20 <-> 10 <-> None

20 found in the list.

40 not found in the list.

Deleted 20 from the list.

Doubly Linked List (Forward):

10 <-> 30 <-> None

Doubly Linked List (Backward):

30 <-> 10 <-> None

40 not found in the list.

Doubly Linked List (Forward):

10 <-> 30 <-> None

Doubly Linked List (Backward):

30 <-> 10 <-> None

12. Write a program to implement Binary Search Tree.

Program:

class TreeNode:

"""A Node of a Binary Search Tree."""

def __init__(self, key):

self.left = None # Pointer to the left child

self.right = None # Pointer to the right child

self.val = key # Store the value of the node

class BinarySearchTree:

"""A Binary Search Tree."""

def __init__(self):
self.root = None # Initialize the root of the tree

def insert(self, key):

"""Insert a new node with the specified key."""

if self.root is None:

self.root = TreeNode(key) # If the tree is empty, set root to the new node

print(f"Inserted {key} as the root node.")

else:

self._insert_recursively(self.root, key)

def _insert_recursively(self, node, key):

"""Helper method to insert a new node recursively."""

if key < node.val: # If the key is smaller, go to the left subtree

if node.left is None:

node.left = TreeNode(key) # Insert the new node

print(f"Inserted {key} to the left of {node.val}.")

else:

self._insert_recursively(node.left, key) # Continue searching

else: # If the key is greater or equal, go to the right subtree

if node.right is None:

node.right = TreeNode(key) # Insert the new node

print(f"Inserted {key} to the right of {node.val}.")

else:

self._insert_recursively(node.right, key) # Continue searching

def search(self, key):

"""Search for a node with the specified key."""

result = self._search_recursively(self.root, key)

if result:

print(f"{key} found in the BST.")

else:

print(f"{key} not found in the BST.")

return result

def _search_recursively(self, node, key):


"""Helper method to search for a key recursively."""

if node is None or node.val == key:

return node # Return the node if found or None if not found

if key < node.val: # Search in the left subtree

return self._search_recursively(node.left, key)

# Search in the right subtree

return self._search_recursively(node.right, key)

def delete(self, key):

"""Delete a node with the specified key."""

self.root = self._delete_recursively(self.root, key)

def _delete_recursively(self, node, key):

"""Helper method to delete a node recursively."""

if node is None:

print(f"{key} not found in the BST. Cannot delete.")

return node # Node not found

if key < node.val: # Go to the left subtree

node.left = self._delete_recursively(node.left, key)

elif key > node.val: # Go to the right subtree

node.right = self._delete_recursively(node.right, key)

else:

# Node with the key found

print(f"Deleting {key}.")

# Node with only one child or no child

if node.left is None:

return node.right

elif node.right is None:

return node.left

# Node with two children, get the inorder successor (smallest in the right subtree)

min_larger_node = self._min_value_node(node.right)

node.val = min_larger_node.val # Copy the inorder successor's value to this node

node.right = self._delete_recursively(node.right, min_larger_node.val) # Delete the inorder successor

return node
def _min_value_node(self, node):

"""Helper method to find the node with the minimum value greater than the given node."""

current = node

while current.left:

current = current.left

return current

def in_order_traversal(self):

"""Perform in-order traversal of the tree."""

print("In-order traversal of the BST:")

self._in_order_traversal_recursively(self.root)

def _in_order_traversal_recursively(self, node):

"""Helper method for in-order traversal recursively."""

if node:

self._in_order_traversal_recursively(node.left)

print(node.val, end=" ")

self._in_order_traversal_recursively(node.right)

# Test the Binary Search Tree implementation

if __name__ == "__main__":

bst = BinarySearchTree()

# Insert nodes

bst.insert(50)

bst.insert(30)

bst.insert(20)

bst.insert(40)

bst.insert(70)

bst.insert(60)

bst.insert(80)

# Display in-order traversal

bst.in_order_traversal()

# Search for nodes

bst.search(40)
bst.search(100)

# Delete nodes

bst.delete(20)

bst.in_order_traversal()

bst.delete(30)

bst.in_order_traversal()

bst.delete(50)

bst.in_order_traversal()

# Attempt to delete a node that does not exist

bst.delete(100)

Output:

Inserted 50 as the root node.

Inserted 30 to the left of 50.

Inserted 20 to the left of 30.

Inserted 40 to the right of 30.

Inserted 70 to the right of 50.

Inserted 60 to the left of 70.

Inserted 80 to the right of 70.

In-order traversal of the BST:

20 30 40 50 60 70 80 40 found in the BST.

100 not found in the BST.

Deleting 20.

In-order traversal of the BST:

30 40 50 60 70 80 Deleting 30.

In-order traversal of the BST:

40 50 60 70 80 Deleting 50.

Deleting 60.

In-order traversal of the BST:

40 60 70 80 100 not found in the BST. Cannot delete.


Example 2 for BST

lass BinaryTreeNode:

def __init__(self, data):

self.data = data

self.leftChild = None

self.rightChild=None

def insert(root,newValue):

#if binary search tree is empty, make a new node and declare it as root

if root is None:

root=BinaryTreeNode(newValue)

return root

#binary search tree is not empty, so we will insert it into the tree

#if newValue is less than value of data in root, add it to left subtree and proceed recursively

if newValue<root.data:

root.leftChild=insert(root.leftChild,newValue)

else:

#if newValue is greater than value of data in root, add it to right subtree and proceed recursively

root.rightChild=insert(root.rightChild,newValue)

return root

root= insert(None,15)

insert(root,10)

insert(root,25)

insert(root,6)

insert(root,14)

insert(root,20)

insert(root,60)

a1=root

a2=a1.leftChild

a3=a1.rightChild
a4=a2.leftChild

a5=a2.rightChild

a6=a3.leftChild

a7=a3.rightChild

print("Root Node is:")

print(a1.data)

print("left child of node is:")

print(a1.leftChild.data)

print("right child of node is:")

print(a1.rightChild.data)

print("Node is:")

print(a2.data)

print("left child of node is:")

print(a2.leftChild.data)

print("right child of node is:")

print(a2.rightChild.data)

print("Node is:")

print(a3.data)

print("left child of node is:")

print(a3.leftChild.data)

print("right child of node is:")

print(a3.rightChild.data)

print("Node is:")

print(a4.data)

print("left child of node is:")

print(a4.leftChild)

print("right child of node is:")

print(a4.rightChild)

print("Node is:")

print(a5.data)

print("left child of node is:")

print(a5.leftChild)
print("right child of node is:")

print(a5.rightChild)

print("Node is:")

print(a6.data)

print("left child of node is:")

print(a6.leftChild)

print("right child of node is:")

print(a6.rightChild)

print("Node is:")

print(a7.data)

print("left child of node is:")

print(a7.leftChild)

print("right child of node is:")

print(a7.rightChild)

Output:

Root Node is:

15

left child of node is:

10

right child of node is:

25

Node is:

10

left child of node is:

right child of node is:

14

Node is:

25

left child of node is:

20
right child of node is:

60

Node is:

left child of node is:

None

right child of node is:

None

Node is:

14

left child of node is:

None

right child of node is:

None

Node is:

20

left child of node is:

None

right child of node is:

None

Node is:

60

left child of node is:

None

right child of node is:

None

You might also like