0% found this document useful (0 votes)
3 views

Python Pca 2

The document outlines various data structure operations including arrays, stacks, queues, and linked lists, demonstrating insertion, deletion, and traversal methods. It provides code examples for implementing these operations in Python, covering both linear and circular structures. Additionally, it discusses the creation and manipulation of binary search trees and AVL trees.

Uploaded by

rakhiray11223344
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Python Pca 2

The document outlines various data structure operations including arrays, stacks, queues, and linked lists, demonstrating insertion, deletion, and traversal methods. It provides code examples for implementing these operations in Python, covering both linear and circular structures. Additionally, it discusses the creation and manipulation of binary search trees and AVL trees.

Uploaded by

rakhiray11223344
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

EXPERIMENT NO1:- Implementation of data structure operations (insertion,

deletion, traversing and searching) in array. Linear search and binary search
Solve:-
Inserting an Element to an array using array module
Program code:
import array
arr1 = array.array('i', [1, 2, 3])
arr2 = array.array('i', [4, 5, 6]) print("arr1 is:", arr1) print("arr2 is:", arr2)
arr3 = arr1 + arr2
print("After arr3 = arr1 + arr2, arr3 is:", arr3)

Output:
arr1 is: array('i', [1, 2, 3])
arr2 is: array('i', [4, 5, 6])
After arr3 = arr1 + arr2, arr3 is: array('i', [1, 2, 3, 4, 5, 6])

 import array
arr1 = array.array('i', [1, 2, 3])
arr2 = array.array('i', [4, 5, 6]) print("arr1 is:", arr1) print("arr2 is:", arr2)
arr1.append(4)
print("\nAfter arr1.append(4), arr1 is:", arr1) arr1.extend(arr2)
print("\nAfter arr1.extend(arr2), arr1 is:", arr1) arr1.insert(0, 10)
print("\nAfter arr1.insert(0, 10), arr1 is:", arr1)

Output:
arr1 is: array('i', [1, 2, 3])
arr2 is: array('i', [4, 5, 6])
After arr1.append(4), arr1 is: array('i', [1, 2, 3, 4])
After arr1.extend(arr2), arr1 is: array('i', [1, 2, 3, 4, 4, 5, 6])
After arr1.insert(0, 10), arr1 is: array('i', [10, 1, 2, 3, 4, 4, 5, 6])

 Deletion an Element to an array using array module:


Program Code:
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
lst.remove(2) print(lst) lst.pop(0) print(lst)
lst.pop() print(lst) del lst[0] print(lst) del lst
lst = [1, 2, 3, 4]
print(lst)
lst.clear() print(lst)

output
[1, 3, 4, 5, 6, 7, 8, 9, 10]
[3, 4, 5, 6, 7, 8, 9, 10]
[3, 4, 5, 6, 7, 8, 9]
[4, 5, 6, 7, 8, 9]
[1, 2, 3, 4]
EXPERIMENT NO2:- Implement of Stack, queue operation using array. Pop,
Push, Insertion, deletion, Implementation of Circular queue. Infix to postfix
expression evaluation. Implementation of stack operations in data structure:

Implementation of stack operations in data structure:


Programme code :
class Stack:
def __init__(self):
self.stack = []
def is_empty(self):
return len(self.stack) == 0
def push(self, item):
self.stack.append(item)
def pop(self):
if not self.is_empty():
return self.stack.pop()
else:
print("Stack is empty. Cannot pop.")
return None
def peek(self):
if not self.is_empty():
return self.stack[-1]
else:
print("Stack is empty. Cannot peek.")
return None

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

stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)

print("Stack:", stack.stack)
print("Peek:", stack.peek())
print("Pop:", stack.pop())
print("Stack:", stack.stack)
print("Is Empty?", stack.is_empty())
print("Stack Size:", stack.size())
output
Stack: [1, 2, 3]
Peek: 3
Pop: 3
Stack: [1, 2]
Is Empty? False
Stack Size: 2

Implementation of circular queue operations in data structure:

class CircularQueue:
def __init__(self, size):
self.maxSize = size
self.queueArray = [0] * size
self.front = -1
self.rear = -1

def enqueue(self, item):


if self.isEmpty():
self.front = 0
self.rear = 0
self.queueArray[self.rear] = item
else:
self.rear = (self.rear + 1) % self.maxSize
if self.rear == self.front:
print("Queue is full. Cannot enqueue.")
self.rear = (self.rear - 1 + self.maxSize) % self.maxSize
else:
self.queueArray[self.rear] = item

def dequeue(self):
item = -1 # Assuming -1 represents an empty value

if not self.isEmpty():
item = self.queueArray[self.front]
if self.front == self.rear:
self.front = -1
self.rear = -1
else:
self.front = (self.front + 1) % self.maxSize
else:
print("Queue is empty. Cannot dequeue.")

return item

def peek(self):
if not self.isEmpty():
return self.queueArray[self.front]
else:
print("Queue is empty. No peek value.")
return -1 # Assuming -1 represents an empty value

def isEmpty(self):
return self.front == -1 and self.rear == -1

if __name__ == "__main__":
circularQueue = CircularQueue(5)

circularQueue.enqueue(1)
circularQueue.enqueue(2)
circularQueue.enqueue(3)

# Should print 1
print("Peek:", circularQueue.peek())

# Should print 1
print("Dequeue:", circularQueue.dequeue())

# Should print 2
print("Peek after dequeue:", circularQueue.peek())

output
Peek: 1
Dequeue: 1
Peek after dequeue: 2
EXPERIMENT NO3:- Implementation of linked lists: Single linked list,
circular linked list, double linked list, doubly circular linked list. Implementation
of stack and queue using linked list. Merging two linked list, Linked list
representation of a polynomial, polynomial addition, polynomial multiplication.

Implementation of single linked list in data structure:

 Insertion of linked list


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

def insert_at_beginning(head, data):


new_node = Node(data)
new_node.next = head
return new_node

def insert_at_end(head, data):


new_node = Node(data)
if head is None:
return new_node

current = head
while current.next:
current = current.next

current.next = new_node
return head

def traverse(head):
current = head
while current:
print(current.data, end=" -> ")
current = current.next
print("None")

head = None
head = insert_at_beginning(head, 3)
head = insert_at_beginning(head, 2)
head = insert_at_beginning(head, 1)

insert_at_end(head, 4)
traverse(head)

output
1 -> 2 -> 3 -> 4 -> None

 Deletion of the Single Linked list


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

def insert_at_beginning(head, data):


new_node = Node(data)
new_node.next = head
return new_node

def delete_at_beginning(head):
if head is None:
print("Error: Singly linked list is empty")
return None

new_head = head.next
del head
return new_head

def traverse(head):
current = head
while current:
print(current.data, end=" -> ")
current = current.next
print("None")

head = None
head = insert_at_beginning(head, 4)
head = insert_at_beginning(head, 3)
head = insert_at_beginning(head, 2)
head = insert_at_beginning(head, 1)

head = delete_at_beginning(head)

traverse(head)

output
2 -> 3 -> 4 -> None

Implementation of the circular linked list in Data Structure:

 Insertion in Circular Linked List:


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

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

def insert_at_beginning(self, data):


new_node = Node(data)
if not self.head:
self.head = new_node
new_node.next = self.head
else:
new_node.next = self.head
temp = self.head
while temp.next != self.head:
temp = temp.next
temp.next = new_node
self.head = new_node

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

linked_list = LinkedList()
linked_list.insert_at_beginning(3)
linked_list.insert_at_beginning(2)
linked_list.insert_at_beginning(1)

print("Linked List after insertion at the beginning:")


linked_list.display()

output
Linked List after insertion at the beginning:
1 -> 2 -> 3 -> ... (circular)

Deletion in Circular Linked List:


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

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

def append(self, data):


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

new_node.next = new_node
self.head = new_node
else:
current = self.head
while current.next != self.head:
current = current.next
current.next = new_node

new_node.next = self.head

def delete_at_beginning(self):
if not self.head:
print("Circular Linked List is empty")
return
if self.head.next == self.head:
self.head = None
return

current = self.head
while current.next != self.head:
current = current.next

current.next = self.head.next
self.head = self.head.next

def display(self):
if not self.head:
print("Circular Linked List is empty")
return
current = self.head
while True:
print(current.data, end=" -> ")
current = current.next
if current == self.head:
break
print("", end="")

circular_list = CircularLinkedList()
circular_list.append(1)
circular_list.append(2)
circular_list.append(3)

print("Circular Linked List before deletion:")


circular_list.display()
print()

circular_list.delete_at_beginning()

print("Circular Linked List after deletion at the beginning:")


circular_list.display()

output
Circular Linked List before deletion:
1 -> 2 -> 3 ->
Circular Linked List after deletion at the beginning:
2 -> 3 ->
Implementation of double linked list in data structure:

 Insertion of double linked list:


class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None

def insert_at_beginning(head, data):


new_node = Node(data)
new_node.next = head
if head:
head.prev = new_node
return new_node

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

head = None
head = insert_at_beginning(head, 3)
head = insert_at_beginning(head, 2)
head = insert_at_beginning(head, 1)

print("Doubly Linked List after insertion at the beginning:")


display(head)

output
Doubly Linked List after insertion at the beginning:
1 <-> 2 <-> 3 <-> None
Deletion of double linked list:
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None

def delete_at_beginning(head):
if head is None:
print("Doubly linked list is empty")
return None

if head.next is None:
return None

new_head = head.next
new_head.prev = None
del head
return new_head

def traverse(head):
current = head
while current:
# Print current node's data
print(current.data, end=" <-> ")
# Move to the next node
current = current.next
print("None")

def insert_at_beginning(head, data):


new_node = Node(data)
new_node.next = head
if head:
head.prev = new_node
return new_node

head = None
head = insert_at_beginning(head, 4)
head = insert_at_beginning(head, 3)
head = insert_at_beginning(head, 2)
head = insert_at_beginning(head, 1)
head = delete_at_beginning(head)
traverse(head)

output
1 <-> 2 <-> 3 <-> 4 <-> None

Implementation of doubly Circular linked list in data structure:

Insertion of the Doubly circular linked list:


class Node:
def __init__(self, x):
self.data = x
self.next = None
self.prev = None

def insertAtBeginning(head, newData):


newNode = Node(newData)

if head is None:

newNode.next = newNode.prev = newNode


head = newNode
else:

last = head.prev

newNode.next = head
newNode.prev = last
head.prev = newNode
last.next = newNode

head = newNode

return head

def printList(head):
if not head:
return
curr = head
while True:
print(curr.data, end=" ")
curr = curr.next
if curr == head:
break
print()

head = Node(10)
head.next = Node(20)
head.next.prev = head
head.next.next = Node(30)
head.next.next.prev = head.next
head.next.next.next = head
head.prev = head.next.next

head = insertAtBeginning(head, 5)
printList(head)

output
5 10 20 30

Implementation of queue using linked list:

class Node:
def __init__(self, new_data):
self.data = new_data
self.next = None

class Queue:
def __init__(self):

self.front = None
self.rear = None

def is_empty(self):

return self.front is None and self.rear is None

def enqueue(self, new_data):

new_node = Node(new_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.is_empty():
print("Queue Underflow")
return

temp = self.front
self.front = self.front.next

if self.front is None:
self.rear = None

def get_front(self):

if self.is_empty():
print("Queue is empty")
return float('-inf')
return self.front.data

def get_rear(self):

if self.is_empty():
print("Queue is empty")
return float('-inf')
return self.rear.data

if __name__ == "__main__":
q = Queue()

q.enqueue(10)
q.enqueue(20)

print("Queue Front:", q.get_front())


print("Queue Rear:", q.get_rear())

q.dequeue()
q.dequeue()
q.enqueue(30)
q.enqueue(40)
q.enqueue(50)

q.dequeue()

print("Queue Front:", q.get_front())


print("Queue Rear:", q.get_rear())
output
Queue Front: 10
Queue Rear: 20
Queue Front: 40
Queue Rear: 50

EXPERIMENT 4: Tree: creating Binary Search tree, recursive and non


recursive traversal of BST, deletion in BST, calculating height of a BST, building
AVL tree.

CREATING BINARY SEARCH TREE:


Class BSTNode:
def __init__(self, val=None):
self.left = None
self.right = None
self.val = val

def insert(self, val):


if not self.val:
self.val = val
return

if self.val == val:
return

if val < self.val:


if self.left:
self.left.insert(val)
return
self.left = BSTNode(val)
return

if self.right:
self.right.insert(val)
return
self.right = BSTNode(val)

def get_min(self):
current = self
while current.left is not None:
current = current.left
return current.val

def get_max(self):
current = self
while current.right is not None:
current = current.right
return current.val

def delete(self, val):


if self == None:
return self
if self.right == None:
return self.left
if self.left == None:
return self.right
if val < self.val:
if self.left:
self.left = self.left.delete(val)
return self
if val > self.val:
if self.right:
self.right = self.right.delete(val)
return self
min_larger_node = self.right
while min_larger_node.left:
min_larger_node = min_larger_node.left
self.val = min_larger_node.val
self.right = self.right.delete(min_larger_node.val)
return self

def exists(self, val):


if val == self.val:
return True

if val < self.val:


if self.left == None:
return False
return self.left.exists(val)

if self.right == None:
return False
return self.right.exists(val)

def preorder(self, vals):


if self.val is not None:
vals.append(self.val)
if self.left is not None:
self.left.preorder(vals)
if self.right is not None:
self.right.preorder(vals)
return vals

def inorder(self, vals):


if self.left is not None:
self.left.inorder(vals)
if self.val is not None:
vals.append(self.val)
if self.right is not None:
self.right.inorder(vals)
return vals

def postorder(self, vals):


if self.left is not None:
self.left.postorder(vals)
if self.right is not None:
self.right.postorder(vals)
if self.val is not None:
vals.append(self.val)
return vals

output
Inorder Traversal: [20, 30, 40, 50, 60, 70, 80]
Preorder Traversal: [50, 30, 20, 40, 70, 60, 80]
Postorder Traversal: [20, 40, 30, 60, 80, 70, 50]
Minimum value: 20
Maximum value: 80
Does 40 exist? True
Does 100 exist? False
Inorder after deleting 20: [30, 40, 50, 60, 70, 80]
DELETION IN BST:
class TreeNode:
def __init__(self, key):
self.key = key
self.left = None
self.right = None

def inorder_traversal(root):
if root:
inorder_traversal(root.left)
print(root.key, end=" ")
inorder_traversal(root.right)

def find_min(node):
current = node
while current.left:
current = current.left
return current

def delete_node(root, key):


if root is None:
return root

# Search for the node to be deleted


if key < root.key:
root.left = delete_node(root.left, key)
elif key > root.key:
root.right = delete_node(root.right, key)
else:
# Node with only one child or no child
if root.left is None:
return root.right
elif root.right is None:
return root.left

# Node with two children: Get the in-order successor


temp = find_min(root.right)

# Copy the in-order successor's content to this node


root.key = temp.key

# Delete the in-order successor


root.right = delete_node(root.right, temp.key)

return root

if __name__ == "__main__":
root = TreeNode(50)
root.left = TreeNode(30)
root.right = TreeNode(70)
root.left.left = TreeNode(20)
root.left.right = TreeNode(40)
root.right.left = TreeNode(60)
root.right.right = TreeNode(80)

print("Original BST:")
inorder_traversal(root)
print("\n")

key_to_delete = 40
root = delete_node(root, key_to_delete)

print(f"BST after deleting {key_to_delete}:")


inorder_traversal(root)

output
Original BST:
20 30 40 50 60 70 80

BST after deleting 40:


20 30 50 60 70 80

CALCULATING HEIGHT OF BST:

# define a Class Tree, to intiate the binary tree


class TreeNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None

def height(root):

# Check if the binary tree is empty


if root is None:
# If TRUE return 0
return 0
# Recursively call height of each node
leftAns = height(root.left)
rightAns = height(root.right)

# Return max(leftHeight, rightHeight) at each iteration


return max(leftAns, rightAns) + 1

# Test the algorithm


root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)

print("Height of the binary tree is: " + str(height(root)))

output
Height of the binary tree is: 3

BUILDING AVL TREE:


import sys

# Create a tree node


class TreeNode(object):
def __init__(self, key):
self.key = key
self.left = None
self.right = None
self.height = 1

class AVLTree(object):

# Function to insert a node


def insert_node(self, root, key):

# Find the correct location and insert the node


if not root:
return TreeNode(key)
elif key < root.key:
root.left = self.insert_node(root.left, key)
else:
root.right = self.insert_node(root.right, key)

root.height = 1 + max(self.getHeight(root.left),
self.getHeight(root.right))

# Update the balance factor and balance the tree


balanceFactor = self.getBalance(root)
if balanceFactor > 1:
if key < root.left.key:
return self.rightRotate(root)
else:
root.left = self.leftRotate(root.left)
return self.rightRotate(root)

if balanceFactor < -1:


if key > root.right.key:
return self.leftRotate(root)
else:
root.right = self.rightRotate(root.right)
return self.leftRotate(root)

return root

# Function to delete a node


def delete_node(self, root, key):

# Find the node to be deleted and remove it


if not root:
return root
elif key < root.key:
root.left = self.delete_node(root.left, key)
elif key > root.key:
root.right = self.delete_node(root.right, key)
else:
if root.left is None:
temp = root.right
root = None
return temp
elif root.right is None:
temp = root.left
root = None
return temp
temp = self.getMinValueNode(root.right)
root.key = temp.key
root.right = self.delete_node(root.right,
temp.key)
if root is None:
return root

# Update the balance factor of nodes


root.height = 1 + max(self.getHeight(root.left),
self.getHeight(root.right))

balanceFactor = self.getBalance(root)

# Balance the tree


if balanceFactor > 1:
if self.getBalance(root.left) >= 0:
return self.rightRotate(root)
else:
root.left = self.leftRotate(root.left)
return self.rightRotate(root)
if balanceFactor < -1:
if self.getBalance(root.right) <= 0:
return self.leftRotate(root)
else:
root.right = self.rightRotate(root.right)
return self.leftRotate(root)
return root

# Function to perform left rotation


def leftRotate(self, z):
y = z.right
T2 = y.left
y.left = z
z.right = T2
z.height = 1 + max(self.getHeight(z.left),
self.getHeight(z.right))
y.height = 1 + max(self.getHeight(y.left),
self.getHeight(y.right))
return y

# Function to perform right rotation


def rightRotate(self, z):
y = z.left
T3 = y.right
y.right = z
z.left = T3
z.height = 1 + max(self.getHeight(z.left),
self.getHeight(z.right))
y.height = 1 + max(self.getHeight(y.left),
self.getHeight(y.right))
return y

# Get the height of the node


def getHeight(self, root):
if not root:
return 0
return root.height

# Get balance factore of the node


def getBalance(self, root):
if not root:
return 0
return self.getHeight(root.left) - self.getHeight(root.right)

def getMinValueNode(self, root):


if root is None or root.left is None:
return root
return self.getMinValueNode(root.left)

def preOrder(self, root):


if not root:
return
print("{0} ".format(root.key), end="")
self.preOrder(root.left)
self.preOrder(root.right)

# Print the tree


def printHelper(self, currPtr, indent, last):
if currPtr != None:
sys.stdout.write(indent)
if last:
sys.stdout.write("R----")
indent += " "
else:
sys.stdout.write("L----")
indent += "| "
print(currPtr.key)
self.printHelper(currPtr.left, indent, False)
self.printHelper(currPtr.right, indent, True)

myTree = AVLTree()
root = None
nums = [33, 13, 52, 9, 21, 61, 8, 11]
for num in nums:
root = myTree.insert_node(root, num)
myTree.printHelper(root, "", True)
key = 13
root = myTree.delete_node(root, key)
print("After Deletion: ")
myTree.printHelper(root, "", True)

output
R----33
L----13
| L----9
| | L----8
| | R----11
| R----21
R----52
R----61

After Deletion:
R----33
L----9
| L----8
| R----21
| L----11
R----52
R----61
EXPERIMENT 5: Implementation of sorting techniques: selection, bubble,
quick sort, insertion sort, merge sort, heap sot, implementation of priority queue.
Hash table implementation.

SELECTION SORT:
# Selection sort in Python
def selectionSort(array, size):

for step in range(size):


min_idx = step
for i in range(step + 1, size):
# to sort in descending order, change > to < in this line
# select the minimum element in each loop
if array[i] < array[min_idx]:
min_idx = i
# put min at the correct position
(array[step], array[min_idx]) = (array[min_idx], array[step])

data = [-2, 45, 0, 11, -9]


size = len(data)
selectionSort(data, size)
print('Sorted Array in Ascending Order:')
print(data)

output
Sorted Array in Ascending Order:
[-9, -2, 0, 11, 45]

BUBBLE SORT:
# Bubble sort in Python
def bubbleSort(array):

# loop to access each array element


for i in range(len(array)):
# loop to compare array elements
for j in range(0, len(array) - i - 1):
# compare two adjacent elements
# change > to < to sort in descending order
if array[j] > array[j + 1]:
# swapping elements if elements
# are not in the intended order
temp = array[j]
array[j] = array[j+1]
array[j+1] = temp
data = [-2, 45, 0, 11, -9]
bubbleSort(data)
print('Sorted Array in Ascending Order:')
print(data)

output
Sorted Array in Ascending Order:
[-9, -2, 0, 11, 45]

QUICK SORT:
# Quick sort in Python

# function to find the partition position


def partition(array, low, high):

# choose the rightmost element as pivot


pivot = array[high]

# pointer for greater element


i = low - 1

# traverse through all elements


# compare each element with pivot
for j in range(low, high):
if array[j] <= pivot:
# if element smaller than pivot is found
# swap it with the greater element pointed by i
i=i+1

# swapping element at i with element at j


(array[i], array[j]) = (array[j], array[i])

# swap the pivot element with the greater element specified by i


(array[i + 1], array[high]) = (array[high], array[i + 1])

# return the position from where partition is done


return i + 1

# function to perform quicksort


def quickSort(array, low, high):
if low < high:

# find pivot element such that


# element smaller than pivot are on the left
# element greater than pivot are on the right
pi = partition(array, low, high)

# recursive call on the left of pivot


quickSort(array, low, pi - 1)
# recursive call on the right of pivot
quickSort(array, pi + 1, high)

data = [8, 7, 2, 1, 0, 9, 6]
print("Unsorted Array")
print(data)

size = len(data)

quickSort(data, 0, size - 1)

print('Sorted Array in Ascending Order:')


print(data)

output
Unsorted Array
[8, 7, 2, 1, 0, 9, 6]

Sorted Array in Ascending Order:


[0, 1, 2, 6, 7, 8, 9]

INSERTION SORT:
# Insertion sort in Python
def insertionSort(array):

for step in range(1, len(array)):


key = array[step]
j = step - 1
# Compare key with each element on the left of it until an element smaller
than it is found
# For descending order, change key<array[j] to key>array[j].
while j >= 0 and key < array[j]:
array[j + 1] = array[j]
j=j-1

# Place key at after the element just smaller than it.


array[j + 1] = key

data = [9, 5, 1, 4, 3]
insertionSort(data)
print('Sorted Array in Ascending Order:')
print(data)

output
Sorted Array in Ascending Order:
[1, 3, 4, 5, 9]

You might also like