Skip to content

Commit cf24e70

Browse files
committed
Graph, heap, binary tree
1 parent d053eba commit cf24e70

File tree

8 files changed

+347
-26
lines changed

8 files changed

+347
-26
lines changed

Data_Structures_ChatGPT.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://chatgpt.com/share/67538240-b1e0-8007-9b72-3fff133c78f5

data_structures/10_Graph/my_graph.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,23 @@ def get_paths(self, start, end, path=[]):
2929

3030
return paths
3131

32-
def get_shortest_paths(self, ):
33-
pass
32+
def get_shortest_path(self, start, end, path=[]):
33+
path = path + [start]
34+
35+
if start == end:
36+
return path
37+
38+
if start not in self.graph_dict:
39+
return None
3440

41+
shortest_path = None
42+
for node in self.graph_dict[start]:
43+
if node not in path:
44+
sp = self.get_shortest_path(node, end, path)
45+
if sp:
46+
if shortest_path is None or len(sp) < len(shortest_path):
47+
shortest_path = sp
48+
return shortest_path
3549

3650
if __name__ == '__main__':
3751

@@ -49,11 +63,11 @@ def get_shortest_paths(self, ):
4963
start = "Mumbai"
5064
end = "Mumbai"
5165

52-
print(f"All paths between: {start} and {end}: ",route_graph.get_paths(start,end))
53-
#print(f"Shortest path between {start} and {end}: ", route_graph.get_shortest_path(start,end))
66+
print(f"\nAll paths between: {start} and {end}:\n" + '\n'.join([' -> '.join(path) for path in route_graph.get_paths(start, end)]))
67+
print(f"\nShortest path between {start} and {end}:\n" + ' -> '.join(route_graph.get_shortest_path(start,end)))
5468

55-
start = "Paris"
56-
end = "Toronto"
69+
start = "Mumbai"
70+
end = "New York"
5771

58-
print(f"All paths between: {start} and {end}: ",route_graph.get_paths(start,end))
59-
#print(f"Shortest path between {start} and {end}: ", route_graph.get_shortest_path(start,end))
72+
print(f"\nAll paths between: {start} and {end}:\n" + '\n'.join([' -> '.join(path) for path in route_graph.get_paths(start, end)]))
73+
print(f"\nShortest path between {start} and {end}:\n" + ' -> '.join(route_graph.get_shortest_path(start,end)))

data_structures/10_Graph/test.ipynb

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"metadata": {},
7+
"outputs": [
8+
{
9+
"name": "stdout",
10+
"output_type": "stream",
11+
"text": [
12+
"3\n",
13+
"2\n",
14+
"0\n",
15+
"1\n"
16+
]
17+
}
18+
],
19+
"source": [
20+
"a=6\n",
21+
"b=5\n",
22+
"print(a//2)\n",
23+
"print(b//2)\n",
24+
"print(a%2)\n",
25+
"print(b%2)"
26+
]
27+
},
28+
{
29+
"cell_type": "code",
30+
"execution_count": 3,
31+
"metadata": {},
32+
"outputs": [
33+
{
34+
"name": "stdout",
35+
"output_type": "stream",
36+
"text": [
37+
"[9, 8, 7, 6, 5, 4, 3]\n"
38+
]
39+
}
40+
],
41+
"source": [
42+
"print([i for i in range(10)[:2:-1]])"
43+
]
44+
},
45+
{
46+
"cell_type": "code",
47+
"execution_count": null,
48+
"metadata": {},
49+
"outputs": [],
50+
"source": []
51+
}
52+
],
53+
"metadata": {
54+
"kernelspec": {
55+
"display_name": "data_analysis",
56+
"language": "python",
57+
"name": "python3"
58+
},
59+
"language_info": {
60+
"codemirror_mode": {
61+
"name": "ipython",
62+
"version": 3
63+
},
64+
"file_extension": ".py",
65+
"mimetype": "text/x-python",
66+
"name": "python",
67+
"nbconvert_exporter": "python",
68+
"pygments_lexer": "ipython3",
69+
"version": "3.12.7"
70+
}
71+
},
72+
"nbformat": 4,
73+
"nbformat_minor": 2
74+
}

data_structures/11_Heap/heap.py

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
'''
2+
# Heap
3+
4+
### What is a Heap?
5+
- A heap is a complete binary tree that satisfies the heap property.
6+
- The heap property states that the key stored in each node is either greater than or equal to (≥) - for a maxheap - or
7+
less than or equal to (≤) - for a min heap - the keys in the node's children, according to some total order.
8+
9+
### Python Library:
10+
- Python has a built-in library called heapq from that provides heap data structure. Ex.:
11+
import heapq
12+
13+
### Time Complexity:
14+
15+
- insert: O(log n)
16+
- get_min: O(1)
17+
- extract_min: O(log n)
18+
- update: O(log n) if we have the index, O(n) if we don't
19+
- build: O(n)
20+
21+
'''
22+
23+
class MinHeap:
24+
def __init__(self, arr=None): # Heapifies the array in O(n) time
25+
self.heap = []
26+
if type(arr) is list:
27+
self.heap = arr.copy()
28+
for i in range(len(self.heap)//2-1, -1, -1):
29+
self._siftdown(i)
30+
31+
def _siftup(self, i):
32+
parent = (i-1)//2
33+
while i != 0 and self.heap[i] < self.heap[parent]:
34+
self.heap[i], self.heap[parent] = self.heap[parent], self.heap[i]
35+
i = parent
36+
parent = (i-1)//2
37+
38+
def _siftdown(self, i):
39+
left = 2*i + 1
40+
right = 2*i + 2
41+
while (left < len(self.heap) and self.heap[i] > self.heap[left]) or (right < len(self.heap) and self.heap[i] > self.heap[right]):
42+
smallest = left if (right >= len(self.heap) or self.heap[left] < self.heap[right]) else right
43+
self.heap[i], self.heap[smallest] = self.heap[smallest], self.heap[i]
44+
i = smallest
45+
left = 2*i + 1
46+
right = 2*i + 2
47+
48+
def insert(self, element):
49+
self.heap.append(element)
50+
self._siftup(len(self.heap)-1)
51+
52+
def get_min(self):
53+
return self.heap[0] if len(self.heap) > 0 else None
54+
55+
def extract_min(self):
56+
if len(self.heap) == 0:
57+
return None
58+
minval = self.heap[0]
59+
self.heap[0], self.heap[-1] = self.heap[-1], self.heap[0]
60+
self.heap.pop()
61+
self._siftdown(0)
62+
return minval
63+
64+
def update_by_index(self, i, new):
65+
old = self.heap[i]
66+
self.heap[i] = new
67+
if new < old:
68+
self._siftup(i)
69+
else:
70+
self._siftdown(i)
71+
72+
def update(self, old, new):
73+
if old in self.heap:
74+
self.update_by_index(self.heap.index(old), new)
75+
76+
class MaxHeap:
77+
def __init__(self, arr=None):
78+
self.heap = []
79+
if type(arr) is list:
80+
self.heap = arr.copy()
81+
for i in range(len(self.heap))[::-1]:
82+
self._siftdown(i)
83+
84+
def _siftup(self, i):
85+
parent = (i-1)//2
86+
while i != 0 and self.heap[i] > self.heap[parent]:
87+
self.heap[i], self.heap[parent] = self.heap[parent], self.heap[i]
88+
i = parent
89+
parent = (i-1)//2
90+
91+
def _siftdown(self, i):
92+
left = 2*i + 1
93+
right = 2*i + 2
94+
while (left < len(self.heap) and self.heap[i] < self.heap[left]) or (right < len(self.heap) and self.heap[i] < self.heap[right]):
95+
biggest = left if (right >= len(self.heap) or self.heap[left] > self.heap[right]) else right
96+
self.heap[i], self.heap[biggest] = self.heap[biggest], self.heap[i]
97+
i = biggest
98+
left = 2*i + 1
99+
right = 2*i + 2
100+
101+
def insert(self, element):
102+
self.heap.append(element)
103+
self._siftup(len(self.heap)-1)
104+
105+
def get_max(self):
106+
return self.heap[0] if len(self.heap) > 0 else None
107+
108+
def extract_max(self):
109+
if len(self.heap) == 0:
110+
return None
111+
maxval = self.heap[0]
112+
self.heap[0], self.heap[-1] = self.heap[-1], self.heap[0]
113+
self.heap.pop()
114+
self._siftdown(0)
115+
return maxval
116+
117+
def update_by_index(self, i, new):
118+
old = self.heap[i]
119+
self.heap[i] = new
120+
if new > old:
121+
self._siftup(i)
122+
else:
123+
self._siftdown(i)
124+
125+
def update(self, old, new):
126+
if old in self.heap:
127+
self.update_by_index(self.heap.index(old), new)
128+
129+
130+
def heapsort(arr):
131+
heap = MinHeap(arr)
132+
return [heap.extract_min() for i in range(len(heap.heap))]
133+
134+
135+
class PriorityQueue:
136+
def __init__(self):
137+
self.queue = MaxHeap()
138+
139+
def enqueue(self, element): # Time complexity is O(log n)
140+
self.queue.insert(element)
141+
142+
def peek(self): # Time complexity is O(1)
143+
return self.queue.get_max()
144+
145+
def dequeue(self, element): # Time complexity is O(log n)
146+
return self.queue.extract_max()
147+
148+
def is_empty(self): # Time complexity is O(1)
149+
return len(self.queue.heap) == 0
150+
151+
def change_priority_by_index(self, i, new): # Time complexity is O(log n) if we have the index
152+
self.queue.update_by_index(i, new)
153+
154+
def change_priority(self, old, new): # Time complexity is O(n) if we don't have the index
155+
self.queue.update(old, new)
156+
157+
import heapq
158+
159+
if __name__ == '__main__':
160+
arr = [-4, 3, 1, 0, 2, 5, 10, 8, 12, 9]
161+
162+
# Using the custom MinHeap class
163+
minheap = MinHeap(arr)
164+
print('Heapmin using the custom MinHeap class:\n', minheap.heap)
165+
minn = minheap.extract_min()
166+
print('Min value', minn)
167+
168+
print()
169+
# Using the built-in heapq library
170+
arr2 = arr.copy()
171+
heapq.heapify(arr2)
172+
print('Heapmin using heapq:\n', arr2)
173+
minnim = heapq.heappop(arr2)
174+
print('Min value: ', minnim)
175+
sorted_arr = [heapq.heappop(arr2) for i in range(len(arr2))]
176+
print('Sorted array using heapify: ', sorted_arr)
177+
178+
print()
179+
# Using the custom MaxHeap class
180+
maxheap = MaxHeap(arr)
181+
print('Heapmax using the custom MaxHeap class:\n', maxheap.heap)
182+
maxn = maxheap.extract_max()
183+
print('Max value: ', maxn)
184+
185+
print()
186+
# Using the built-in heapq library
187+
arr3 = [-x for x in arr]
188+
heapq.heapify(arr3)
189+
print('Heapmax with neg sign using heapq:\n', arr3)
190+
maxn = -heapq.heappop(arr3)
191+
print('Max value: ', maxn)
192+
sorted_arr = [-heapq.heappop(arr3) for i in range(len(arr3))]
193+
194+
195+
196+

data_structures/6_Queue/binary_numbers_exercise.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
from collections import deque
33

4-
class Queue:
4+
class dQueue:
55
def __init__(self):
66
self.buffer = deque()
77

@@ -27,7 +27,7 @@ def size(self):
2727

2828

2929
def print_binary(end):
30-
queue = Queue()
30+
queue = dQueue()
3131
queue.enqueue('1')
3232

3333
for i in range(end):
@@ -36,10 +36,23 @@ def print_binary(end):
3636

3737
queue.enqueue(binary_number + '0')
3838
queue.enqueue(binary_number + '1')
39-
4039

40+
# Using queue python library
41+
from queue import Queue
42+
def print_binary_2(end):
43+
queue = Queue()
44+
queue.put('1')
45+
46+
for i in range(end):
47+
binary_number = queue.get()
48+
print(' ' + binary_number)
49+
50+
queue.put(binary_number + '0')
51+
queue.put(binary_number + '1')
4152

4253

4354
if __name__ == '__main__':
4455

45-
print_binary(12)
56+
print_binary(12)
57+
print()
58+
print_binary_2(12)

data_structures/8_Binary_Tree_1/binary_tree_part_1_exercise.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def find_max(self):
8383
def find_min(self):
8484
if self.left is None:
8585
return self.data
86-
return self.left.find_max()
86+
return self.left.find_min()
8787

8888
def calculate_sum(self):
8989
return sum(self.in_order_traversal())

data_structures/8_Binary_Tree_1/binary_tree_terms.ipynb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
"- **Parent**: A node that has one or more child nodes.\n",
1313
"- **Child**: A node that has a parent node.\n",
1414
"- **Leaf**: A node that has no children.\n",
15-
"- **Height**: The number of edges on the longest path between the root and a leaf.\n",
15+
"- **Height of a tree**: The number of edges on the longest path between the root and a leaf.\n",
1616
" - Height of an empty tree is -1.\n",
17+
"- **Depth of a node**: The number of edges on the path between the root and the node.\n",
18+
" - Depth of the root is 0.\n",
1719
"\n",
1820
"- **Complete Binary Tree**: A binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.\n",
1921
"- **Perfect Binary Tree**: A binary tree in which all interior nodes have two children and all leaves have the same depth.\n",
@@ -25,6 +27,7 @@
2527
"\n",
2628
"### Properties\n",
2729
"\n",
30+
"\n",
2831
"- The maximum number of nodes at level $l$ of a binary tree is $2^l$.\n",
2932
"- The maximum number of nodes in a binary tree of height $h$ is $2^{h+1}-1$.\n",
3033
"- In a binary tree with $n$ nodes:\n",

0 commit comments

Comments
 (0)