Understanding Data Structures Basics
Understanding Data Structures Basics
4. Homogeneous Vs Non-Homogeneous
Data Structures:
Homogeneous Data Structures:
Store data elements of the same data type. Examples: an array
of integers.
2. Operating Systems
Operating systems utilize data structures like queues for process
scheduling, stacks for managing function calls and memory
allocation, and linked lists for managing file systems and free
memory blocks.
3. Compiler Design
Compilers employ data structures such as symbol tables to store
information about variables and functions, abstract syntax trees
(ASTs) to represent the structure of source code, and hash tables
for efficient symbol lookup.
4. Computer Graphics
Data structures like trees (e.g., k-d trees, octrees) and graphs are
used to represent and manipulate geometric objects, manage
spatial data, and optimize rendering processes in computer
graphics applications.
5. Networking
Graphs are extensively used to model network topologies,
represent routing paths, and implement routing algorithms. Queues
are used for managing data packets in network communication.
7. Navigation Systems
Graphs are used to represent road networks, and algorithms like
Dijkstra's or A* search, often implemented with priority queues, are
used to find optimal routes.
8. File Systems
Data structures like trees (e.g., directory trees) and linked lists
(e.g., for file allocation tables) are used to organize and manage
files and directories on storage devices.
What is Array?
Array is a linear data structure where all elements are
arranged sequentially. It is a collection of elements of
same data type stored at contiguous memory locations.
arr = array('i',[10,20,30,40])
print(arr)
## add element
[Link](50)
print('After append: ',arr)
## insert at index
[Link](1,15)
print('After insert: ',arr)
## update at index
arr[2] = 25
print('after update: ',arr)
## Remove element
[Link](15)
print('After remove 15: ',arr)
In Python
All Python lists are implemented as dynamic referential
arrays:
The list grows dynamically (Dynamic Array behavior)
Stores references to Python objects (Referential Array concept)
for num in L:
print(num, 'at Address: ',id(num))
1 at Address: 140705501639592
hello at Address: 2880318671584
2 at Address: 140705501639624
python at Address: 2880223635776
3.14 at Address: 2880320665968
True at Address: 140705500754352
In [33]: L = ['hello','python',10,20,30,3.4,True]
## Searching
print([Link](30))
## Sorting
L1 = [10,44,32,11,65,71,17]
[Link]()
print(L1)
## Indexing
print(L1[0])
print(L1[-1])
## Slicing
## reverse elements
print(L1[::-1])
def __len__(self):
return self.n
def __str__(self):
res = ''
for i in range(self.n):
res = res + str(self.A[i]) + ','
return '[' + res[:-1] + ']'
def append(self,item):
# first check array is full or not
if [Link] == self.n:
# full h - resize array
self.__resize_array([Link]*2)
# jagah h
self.A[self.n] = item
self.n += 1
def pop(self):
if self.n == 0:
return 'List Empty'
print(self.A[self.n-1])
self.n -= 1
def __getitem__(self,index):
## slicing
if isinstance(index,slice):
start,stop,step=[Link](self.n)
result = [self.A[i] for i in range(start,stop,step)]
return result
def __delitem__(self,pos):
if 0 <= pos< self.n:
## delete
for i in range(pos,self.n-1):
# shifting
self.A[i] = self.A[i+1]
self.n -= 1
# searching
def index(self,value):
for i in range(self.n):
if self.A[i]==value:
return i
return 'Not Found'
# sorting
def sort(self):
for i in range(self.n):
for j in range(0,self.n-i-1):
if self.A[j]>self.A[j+1]:
self.A[j],self.A[j+1] = self.A[j+1],self.A[j]
# insert
def insert(self,pos,value):
if [Link]==self.n:
self.__resize_array([Link]*2)
## agar jagah h
for i in range(self.n,pos,-1):
# shifting
self.A[i] = self.A[i-1]
self.A[pos]=value
self.n +=1
# remove
def remove(self,value):
# find index position
pos = [Link](value)
if type(pos)==int:
# if index found
self.__delitem__(pos)
else:
# index not found
return pos
# extend
def extend(self,iterable):
for item in iterable:
if self.n == [Link]:
self.__resize_array([Link]*2)
self.A[self.n] = item
self.n += 1
# merge
def merge(self,other):
merged = List()
# all elements from list 1
for i in range(self.n):
[Link](self.A[i])
# all elements from list2
for i in range(len(other)):
[Link](other[i])
return merged
# reverse
def reverse(self):
start = 0
end = self.n - 1
while start<end:
self.A[start],self.A[end] = self.A[end],self.A[start]
start += 1
end -= 1
return self
# min elements
def min(self):
min_val = self.A[0]
for i in range(self.n):
if self.A[i]<min_val:
min_val = self.A[i]
return min_val
# max elements
def max(self):
max_val = self.A[0]
for i in range(self.n):
if self.A[i]>max_val:
max_val = self.A[i]
return max_val
# sum of elements
def sum(self):
sum = 0
for i in range(self.n):
sum += self.A[i]
return sum
## advanced function
## [Link] elements frequency
def count(self,item):
count = 0
for i in range(self.n):
if self.A[i]==item:
count+=1
return count
def __make_array(self,capacity):
# create ctypes array with capacity
return (capacity*ctypes.py_object)()
def __resize_array(self,new_capacity):
# create an new array with double size
B = self.__make_array(new_capacity)
# update capacity
[Link] = new_capacity
# re-assign B to A
self.A = B
In [199… L = List()
## append elements
[Link](71)
[Link](12)
[Link](33)
[Link](46)
[Link](25)
print('List: ',L)
print('Length: ',len(L))
print('Index of 4: ',[Link](4))
print('First Element: ',L[0])
print('Last Element: ',L[-1])
[Link]()
print('Sorted Array: ',L)
## remove
[Link](44)
print('after remove: ',L)
## extend list
[Link]([115,116])
print('after extend: ',L)
## merged list
merged_array = [Link]([44,55,66])
print('merged array: ',merged_array)
## reverse list
print('reverse array: ',[Link]())
L.remove_duplicates()
print('After Remove Duplicated: ',L)
## binary search
print('Binary Search element-116 : ',L.binary_search(115))
List: [71,12,33,46,25]
Length: 5
Index of 4: Not Found
First Element: 71
Last Element: 25
Sorted Array: [12,25,33,46,71]
after insert: [12,91,25,44,33,46,71]
after delete: [91,25,44,33,46,71]
after remove: [91,25,33,46,71]
after extend: [91,25,33,46,71,115,116]
merged array: [91,25,33,46,71,115,116,44,55,66]
reverse array: [116,115,71,46,33,25,91]
Min Elements: 25
Max Elements: 116
Sum of Elements: 497
Count 71: 3
Count 115: 2
Count 1158: 0
Duplicate Array: [116,115,71,46,33,25,91,116,115,71,71]
After Remove Duplicated: [116,115,71,46,33,25,91]
after sorted: <__main__.py_object_Array_16 object at 0x0000029EA1A35550>
Binary Search element-116 : 5
linear_search([2,5,7,11,19,15],15)
Out[1]: 5
[Link] Search
In [6]: def binary_search(arr,item):
low=0
high = len(arr)-1
while low<=high:
mid=(low+high)//2
if arr[mid]==item:
return mid
if arr[mid]<item:
low = mid+1
else:
high = mid-1
return -1
binary_search([2,3,5,7,11],7)
Out[6]: 3
Sorting
1. Bubble Sort
Bubble Sort is the simplest sorting algorithm that works
by repeatedly swapping the adjacent elements if they
are in the wrong order. This algorithm is not suitable for
large data sets as its average and worst-case time
complexity are quite high.
Compare the first two values and swap if necessary. Then compare
the next pair of values and swap if necessary. This process is
repeated n-1 times, where n is the number of values being sorted.
The example above sorts 4 numbers into ascending numerical
order. As you can see, this requires 3 (n-1) passes to achieve since
there are 4 items of data. The bigger numbers can be seen to
bubble (or ripple) to the top
bubble_sort([21,81,12,78,89,97])
2. Selection Sort
Selection Sort is a comparison-based sorting algorithm.
It sorts an array by repeatedly selecting the smallest (or
largest) element from the unsorted portion and
swapping it with the first unsorted element. This
process continues until the entire array is sorted.
selection_sort([34,12,21,65,11])
return
def merge_sort(arr):
if len(arr)==1:
return arr
mid = len(arr)//2
left = arr[:mid]
right = arr[mid:]
merge_sort(left)
merge_sort(right)
merge_sorted_arrays(left,right,arr)
return arr
merge_sort([89,14,55,61,34])
Time Complexity:
Best Case: O(n log n), When the array is already sorted or nearly sorted.
Average Case: O(n log n), When the array is randomly ordered.
Worst Case: O(n log n), When the array is sorted in reverse order.
Disadvantages
Space complexity: Merge sort requires additional memory to store the
merged sub-arrays during the sorting process.
Not in-place: Merge sort is not an in-place sorting algorithm, which means
it requires additional memory to store the sorted data. This can be a
disadvantage in applications where memory usage is a concern.
Merge Sort is Slower than QuickSort in general as QuickSort is more cache
friendly because it works in-place.
4. Quick Sort
QuickSort is a sorting algorithm based on the Divide and
Conquer that picks an element as a pivot and partitions
the given array around the picked pivot by placing the
pivot in its correct position in the sorted array.
In [20]: def quick_sort(arr):
if len(arr)<1:
return arr
pivot = arr[len(arr)//2]
Auxiliary Space:
Worst-case scenario: O(n) due to unbalanced partitioning leading to a
skewed recursion tree requiring a call stack of size O(n).
Best-case scenario: O(log n) as a result of balanced partitioning leading to a
balanced recursion tree with a call stack of size O(log n
LinkedList
A linked list is a type of linear data structure similar to arrays. It is a
collection of nodes that are linked with each other. A node contains
two things first is data and second is a link that connects it with
another node. Below is an example of a linked list with four nodes
and each node contains character data and a link to another node.
Our first node is where head points and we can access all the
elements of the linked list using the head.
# Link Nodes
[Link] = node2
[Link] = node3
[Link] = node4
while current:
print([Link],end='->')
current = [Link]
print('None')
10->20->30->40->None
Types Of LinkedList
1. Singly LinkedList
A singly linked list is a fundamental data structure, it consists of
nodes where each node contains a data field and a reference to the
next node in the linked list. The next of the last node is null,
indicating the end of the list. Linked Lists support efficient insertion
and deletion operations.
2. Dobly LinkedList
A doubly linked list is a more complex data structure than a singly
linked list, but it offers several advantages. The main advantage of
a doubly linked list is that it allows for efficient traversal of the list
in both directions. This is because each node in the list contains a
pointer to the previous node and a pointer to the next node. This
allows for quick and easy insertion and deletion of nodes from the
list, as well as efficient traversal of the list in both directions.
3. Circular LinkedList
A circular linked list is a data structure where the last node points
back to the first node, forming a closed loop.
Structure: All nodes are connected in a circle, enabling continuous traversal
without encountering NULL.
Difference from Regular Linked List: In a regular linked list, the last node
points to NULL, whereas in a circular linked list, it points to the first node.
Uses: Ideal for tasks like scheduling and managing playlists, where smooth
and repeated.
In Circular Singly Linked List, each node has just one pointer called
the "next" pointer. The next pointer of the last node points back to
the first node and this results in forming a circle. In this type of
Linked list, we can only move through the list in one direction.
In circular doubly linked list, each node has two pointers prev and
next, similar to doubly linked list. The prev pointer points to the
previous node and the next points to the next node. Here, in
addition to the last node storing the address of the first node, the
first node will also store the address of the last node.
Advantages
Efficient Traversal
No Null Pointers/References
Useful for Repetitive Tasks
Insertion at Beginning or End is O(1)
Uniform Traversal
Efficient Memory Utilization
Disadvantages
Complex Implementation
Infinite Loop Risk
Harder to debug
Deletion Complexity
Memory Overhead (for Doubly Circular LL)
Not cache friendly
# create Nodes
n1 = Node(10)
n2 = Node(20)
n3 = Node(30)
n4 = Node(40)
# link Nodes
[Link] = None
[Link] = n2
[Link] = n1
[Link] = n3
[Link] = n2
[Link] = n4
[Link] = n3
[Link] = None
head = n1
current = head
while current:
print([Link], end= '->')
current = [Link]
print('None')
10->20->30->40->None
# create Nodes
n1 = Node(10)
n2 = Node(20)
n3 = Node(30)
n4 = Node(40)
# LinkedNodes
[Link] = n2
[Link] = n3
[Link] = n4
[Link] = n1
# traverse
head = n1
current = head
while True:
print([Link],end='->')
current = [Link]
if current== head:
break
print('None')
10->20->30->40->None
# create Nodes
n1 = Node(10)
n2= Node(20)
n3= Node(30)
n4 = Node(40)
# LinkedNodes
[Link] = n4
[Link] = n2
[Link] = n1
[Link] = n3
[Link] = n2
[Link] = n4
[Link] = n3
[Link] = n1
# traverse
head = n1
current = head
while True:
print([Link],end='->')
current = [Link]
if current==head:
break
print('None')
10->20->30->40->None
class LinkedList:
def __init__(self):
[Link] = None
self.n = 0
def __len__(self):
return self.n
def __str__(self):
curr = [Link]
res = ''
while curr:
res += str([Link]) + ' -> '
curr = [Link]
return res + 'None'
def insert_head(self,item):
# create an Node
new_node = Node(item)
new_node.next = [Link]
[Link] = new_node
self.n += 1
def append(self,item):
new_node = Node(item)
curr = [Link]
def insert_after(self,after,item):
new_node = Node(item)
curr = [Link]
while [Link]!=None:
if [Link] == after:
break
curr = [Link]
new_node.next = [Link]
[Link] = new_node
self.n += 1
def delete_head(self):
if [Link] == None:
return 'Empty LL'
[Link] = [Link]
self.n -= 1
def pop(self):
if [Link]==None:
return 'Empty LL'
curr = [Link]
while [Link]!=None:
curr = [Link]
[Link] = None
self.n -= 1
def remove(self,value):
if [Link] == value:
self.delete_head()
return
curr = [Link]
while [Link]!=None:
if [Link] == value:
break
curr = [Link]
if [Link]!=None:
[Link] = [Link]
self.n -= 1
else:
return 'Not found'
def search(self,value):
curr = [Link]
pos = 0
while curr!=None:
if [Link] == value:
return pos
curr = [Link]
pos += 1
def reverse(self):
prev = None
curr = [Link]
while curr!=None:
next_node = [Link]
[Link] = prev
prev = curr
curr = next_node
[Link]=prev
def min(self):
curr = [Link]
min_val = [Link]
while curr!=None:
if [Link]<min_val:
min_val = [Link]
curr = [Link]
return min_val
def max(self):
curr = [Link]
max_val = [Link]
while curr!=None:
if [Link]>max_val:
max_val = [Link]
curr = [Link]
return max_val
def __getitem__(self,index):
curr = [Link]
pos = 0
while curr!=None:
if pos==index:
return [Link]
curr = [Link]
pos += 1
l = LinkedList()
l.insert_head(1)
[Link](2)
[Link](3)
[Link](4)
[Link](5)
print(l)
[Link]()
print(l)
l.delete_head()
print(l)
[Link](4)
print(l)
# search
print([Link](3))
# get index
print(l[0])
[Link](12)
[Link](43)
[Link](40)
print(l)
[Link]()
print(l)
print('Min: ',[Link]())
print('Max: ',[Link]())
print('Length: ',len(l))
Stack
A stack is a linear data structure that follows the Last-In/First-Out
(LIFO) principle, also known as First-In/Last-Out (FILO). This means
that the last element added is the first one to be removed. In a
stack, both insertion and deletion happen at the same end, which is
called the top of the stack.
Stack Operations
Stacks support a small set of basic operations, all of which run in O
(1) time:
empty (): checks if the stack is empty
size (): returns the number of elements in the stack
top () / peek (): shows the top element without removing it
push(a): adds an element a at the top
pop (): removes the top element
class LStack:
def __init__(self):
[Link] = None
def is_empty(self):
return [Link]==None
def peek(self):
if (self.is_empty()):
return 'Empty Stack'
return [Link]
def push(self,value):
new_node = Node(value)
new_node.next = [Link]
[Link] = new_node
def pop(self):
if (self.is_empty()):
return 'Empty Stack'
else:
data = [Link]
[Link] = [Link]
return data
def traverse(self):
temp = [Link]
while (temp!=None):
print([Link])
temp = [Link]
def size(self):
temp = [Link]
counter = 0
while temp!=None:
counter+=1
temp=[Link]
return counter
In [68]: s = LStack()
[Link](1)
[Link](2)
[Link](3)
[Link](4)
[Link]()
[Link]()
[Link]()
print('*'*20)
[Link]()
print('peek:',[Link]())
print('size: ',[Link]())
print('check empty: ',s.is_empty())
4
3
2
1
********************
2
1
peek: 2
size: 2
check empty: False
def is_empty(self):
return [Link] == -1
def push(self,value):
if [Link] == [Link] -1:
return 'overflow'
else:
[Link] += 1
[Link][[Link]]=value
def pop(self):
if [Link] == -1:
return 'empty stack'
else:
data = [Link][[Link]]
[Link] -= 1
return data
def peek(self):
if [Link] == -1:
return 'empty stack'
return [Link][[Link]]
def traverse(self):
for i in range([Link]+1):
print([Link][i])
def __len__(self):
counter = 0
for i in range([Link]+1):
counter+=1
return counter
In [66]: s = AStack(3)
[Link](1)
[Link](2)
[Link](3)
[Link]()
[Link]()
print('*'*20)
[Link]()
print('peek:',[Link]())
print('size: ',len(s))
print('check empty: ',s.is_empty())
1
2
3
********************
1
2
peek: 2
size: 2
check empty: False
Stack Programs
Function Signature
def reverse_string(text: str) -> str:
Examples
Example 1:
Example 2:
Constraints
0 <= len(text) <= 10^5
text consists of printable ASCII characters.
Hint
Use a stack to push each character of the string.
Pop each character from the stack and append it to a new string.
The popped sequence will form the reversed string.
In [69]: def rev_string(text):
s = LStack()
for i in text:
[Link](i)
res = ''
while (not s.is_empty()):
res = res + [Link]()
return res
rev_string('hello moto')
📝 Description
Initially, the editor is given a string text .
You are also given a sequence of operations pattern , where each character
in the pattern can be:
'u' → Undo the last action (move one character from the undo stack to
the redo stack)
'r' → Redo the last undone action (move one character from the redo
stack back to the undo stack)
After performing all operations, return the final text present in the undo stack.
🔹 Function Signature
def text_editor(text: str, pattern: str) -> str:
⚙️Example
Input:
text = "abcd"
pattern = "uur"
Constraints
🧩 Hint
for i in text:
[Link](i)
for i in pattern:
if i == 'u':
data = [Link]()
[Link](data)
elif i == 'r':
data = [Link]()
[Link](data)
res = ''
while (not u.is_empty()):
res = [Link]() + res
return res
text_editor('hello moto','uuurrru')
1. Is known by everyone.
2. Knows no one.
Your task: Identify the celebrity (return their index) or state that no celebrity
exists.
Function Signature
def find_celeb(L: list[list[int]]) -> None:
python
L = [
[0, 1, 1],
[0, 0, 1],
[0, 0, 0]
]
Hint:
Use a stack to efficiently find the celebrity:
1. Push all indices (0 to n-1) onto the stack.
2. Pop two indices i and j :
If i knows j , i cannot be celebrity → push j back
Else, j cannot be celebrity → push i back
3. The last remaining person is a potential celebrity.
4. Verify:
They know no one
Everyone else knows them
Time Complexity reduces from O(n²) to O(n).
for i in range(len(L)):
[Link](i)
while [Link]()>=2:
i = [Link]()
j = [Link]()
if L[i][j]==0:
# means - i not knows j - j not celebirity
[Link](i)
else:
# means j not knows i - i not celibrity
[Link](j)
celeb = [Link]()
for i in range(len(L)):
if i!=celeb:
if L[i][celeb] == 0 or L[celeb][i]==1:
print('No one is celebrity')
return
L1 = [
[0, 1, 1],
[0, 0, 1],
[0, 0, 0]
]
find_celeb(L1)
L2 = [
[0, 1, 0],
[0, 0, 1],
[1, 0, 0]
]
find_celeb(L2)
the celibrity is 2
No one is celebrity
Function Signature
def valid_parenthesis(text: str) -> bool:
Examples
Example 1:
Explanation: All opening brackets are closed properly in the correct order.
Example 2:
Example 3:
Constraints
1 <= len(text) <= 10^4
text consists only of '(' , ')' , '{' , '}' , '[' , ']' .
Hint
Use a stack to track opening brackets.
For every closing bracket, check if it matches the top of the stack.
If it matches, pop the stack; otherwise, the string is invalid.
After processing all characters, the stack should be empty for a valid string.
print(valid_parenthesis("()[]{}"))
print(valid_parenthesis("([)])"))
print(valid_parenthesis("{[]}"))
True
False
True
Queue in Python
Queue is a linear data structure that stores items in a
First In First Out (FIFO) manner. The item that is added
first will be removed first. Queues are widely used in
real-life scenarios, like ticket booking, or CPU task
scheduling, where first-come, first-served rule is
followed.
Operations associated with queue are:
Enqueue: Adds an item to the queue. If queue is full, it is said to be an
Overflow condition – Time Complexity : O(1)
Dequeue: Removes an item from the queue. If the queue is empty, it is said
to be an Underflow condition – Time Complexity : O(1)
Front: Get front item from queue – Time Complexity : O(1)
Rear: Get last item from queue – Time Complexity : O(1)
class Queue:
def __init__(self):
[Link] = None
[Link] = None
def enqueue(self,value):
new_node = Node(value)
if [Link] == None:
[Link] = new_node
[Link] = [Link]
else:
[Link] = new_node
[Link] = new_node
def dequeue(self):
if [Link] == None:
return 'Empty Queue'
else:
[Link] = [Link]
def traverse(self):
temp = [Link]
while temp!=None:
print([Link],end=' ')
temp = [Link]
print()
def front_item(self):
if [Link] == None:
return 'Empty Queue'
return [Link]
def rear_item(self):
if [Link] == None:
[Link] = [Link]
return [Link]
def size(self):
counter = 0
temp = [Link]
while temp!=None:
counter+=1
temp = [Link]
return counter
In [97]: q = Queue()
[Link](1)
[Link](2)
[Link](3)
[Link](4)
[Link]()
[Link]()
[Link]()
print('*'*20)
[Link]()
print('Front: ',q.front_item())
print('rear: ',q.rear_item())
print('Size: ',[Link]())
1 2 3 4
********************
3 4
Front: 3
rear: 4
Size: 2
H + 1 , H + 4 , H + 9 , H + 16
...................... H + k 2
This method is also known as the mid-square method because in this method we
look for i2-th probe (slot) in i-th iteration and the value of i = 0, 1, . . . n – 1.
def put(self,key,value):
## we find index using hash fn
hash_value = self.hash_function(key)
## for quadratic probing
i=0
if [Link][hash_value]==None:
[Link][hash_value]=key
[Link][hash_value]=value
else:
if [Link][hash_value]==key:
[Link][hash_value]=value
else:
while [Link][hash_value]!=None and [Link][hash_value
new_hash_value = [Link](hash_value)
i+=1
if [Link][new_hash_value]==None:
[Link][new_hash_value]=key
[Link][new_hash_value]=value
else:
[Link][new_hash_value]=value
def get(self,key):
# calculate hash
start_position = self.hash_function(key)
current_position = start_position
while [Link][current_position]!=None:
if [Link][current_position]==key:
return [Link][current_position]
current_position = [Link](current_position)
if current_position == start_position:
return 'Item Not Found'
return 'Not Found'
def __setitem__(self,key,value):
return [Link](key,value)
def __getitem__(self,key):
return [Link](key)
def __str__(self):
for i in range(len([Link])):
print([Link][i],':',[Link][i])
return ''
def __len__(self):
return len([Link])
def hash_function(self,key):
return abs(hash(key)) % [Link]
def rehash(self,old_hash):
return (old_hash + 1) % [Link]
In [56]: d1 = Dictionary(3)
[Link]('python',100)
[Link]('java',200)
d1['php'] = 300
In [57]: print([Link])
print([Link])
In [58]: [Link]('python')
Out[58]: 100
In [59]: [Link]('java')
Out[59]: 200
In [60]: [Link]('c++')
In [61]: print(d1)
php : 300
python : 100
java : 200
In [62]: print(len(d1))
class LL:
def __init__(self):
[Link] = None
def add(self,key,value):
new_node = Node(key,value)
if [Link] == None:
[Link] = new_node
else:
temp = [Link]
while [Link]!=None:
temp=[Link]
[Link] = new_node
def delete_head(self):
if [Link] == None:
return 'Empty'
[Link] = [Link]
def remove(self,key):
if [Link] == key:
self.delete_head()
return
if [Link] == None:
return 'Empty'
temp = [Link]
while temp!=None:
if [Link] == key:
break
temp = [Link]
[Link] = [Link]
def traverse(self):
temp = [Link]
while temp!=None:
print([Link],':',[Link])
temp=[Link]
def search(self,key):
temp = [Link]
pos = 0
while temp!=None:
if [Link]==key:
return pos
temp=[Link]
pos += 1
return -1
def size(self):
temp = [Link]
counter = 0
while temp!=None:
counter += 1
temp = [Link]
return counter
def get_node_at_index(self,index):
temp=[Link]
counter=0
while temp!=None:
if counter==index:
return temp
temp= [Link]
counter += 1
class Dict:
[Link] = capacity
[Link] = 0
# create array of LL
[Link] = self.make_array([Link])
def make_array(self,capacity):
L = []
for i in range(capacity):
[Link](LL())
return L
def __setitem__(self,key,value):
[Link](key,value)
def __getitem__(self,key):
return [Link](key)
def __delitem__(self,key):
bucket_index = self.hash_function(key)
[Link][bucket_index].remove(key)
def __str__(self):
for i in [Link]:
[Link]()
return ""
def __len__(self):
return [Link]
def get(self,key):
bucket_index = self.hash_function(key)
res = [Link][bucket_index].search(key)
if res == -1:
return "Not Present"
else:
node = [Link][bucket_index].get_node_at_index(res)
return [Link]
bucket_index = self.hash_function(key)
if node_index == -1:
# insert
[Link][bucket_index].add(key,value)
[Link]+=1
load_factor = [Link]/[Link]
def rehash(self):
[Link] = [Link] * 2
old_buckets = [Link]
[Link] = 0
[Link] = self.make_array([Link])
for i in old_buckets:
for j in range([Link]()):
node = i.get_node_at_index(j)
key_item = [Link]
value_item = [Link]
[Link](key_item,value_item)
node_index = [Link][bucket_index].search(key)
return node_index
def hash_function(self,key):
return abs(hash(key)) % [Link]
In [148… d1 = Dict(3)
[Link]('python',1)
[Link]('java',2)
[Link]('php',3)
[Link]('go',4)
[Link]('html',5)
[Link]('css',6)
In [149… d1['python']=100
In [150… print(d1)
php : 3
python : 100
go : 4
java : 2
html : 5
css : 6
In [151… d1['matlab']=300
In [152… print(d1)
php : 3
python : 100
go : 4
matlab : 300
java : 2
html : 5
css : 6
In [155… print(d1)
php : 3
python : 100
go : 4
java : 2
html : 5
css : 6