Skip to content

Commit c1c6f97

Browse files
authored
Update README.md
1 parent 95360e0 commit c1c6f97

File tree

1 file changed

+310
-1
lines changed

1 file changed

+310
-1
lines changed

README.md

+310-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,310 @@
1-
# DSA-Python
1+
Sure! Here's the content with notes and code separated.
2+
3+
---
4+
5+
### **Data Structures and Algorithms in Python**
6+
7+
#### **1. Data Structures**
8+
9+
##### **1.1 Arrays (Lists in Python)**
10+
**Notes**:
11+
An array (or list in Python) is a collection of elements identified by an index or key. Lists in Python are dynamic, meaning they can grow or shrink in size. Lists can store elements of various types (e.g., integers, strings, etc.).
12+
13+
- Operations:
14+
- **Access**: `arr[index]`
15+
- **Insert**: `arr.append(value)` or `arr.insert(index, value)`
16+
- **Remove**: `arr.remove(value)` or `arr.pop(index)`
17+
- **Traverse**: Loop through the list.
18+
19+
**Code**:
20+
```python
21+
# Example of list usage
22+
arr = [1, 2, 3, 4, 5]
23+
arr.append(6) # Add 6 at the end
24+
arr.insert(2, 9) # Insert 9 at index 2
25+
arr.remove(4) # Remove first occurrence of 4
26+
print(arr)
27+
```
28+
29+
##### **1.2 Linked List**
30+
**Notes**:
31+
A linked list is a linear collection of elements called nodes. Each node contains a value and a reference (or pointer) to the next node in the sequence.
32+
33+
- **Types**:
34+
- **Singly Linked List**: Each node points to the next.
35+
- **Doubly Linked List**: Each node points to both the next and the previous node.
36+
37+
- **Basic Operations**:
38+
- **Insertion**: At the beginning, end, or a specific index.
39+
- **Deletion**: At the beginning, end, or a specific node.
40+
41+
**Code**:
42+
```python
43+
class Node:
44+
def __init__(self, data):
45+
self.data = data
46+
self.next = None
47+
48+
class LinkedList:
49+
def __init__(self):
50+
self.head = None
51+
52+
def append(self, data):
53+
new_node = Node(data)
54+
if not self.head:
55+
self.head = new_node
56+
return
57+
last = self.head
58+
while last.next:
59+
last = last.next
60+
last.next = new_node
61+
62+
def display(self):
63+
current = self.head
64+
while current:
65+
print(current.data, end=" -> ")
66+
current = current.next
67+
print("None")
68+
69+
ll = LinkedList()
70+
ll.append(10)
71+
ll.append(20)
72+
ll.append(30)
73+
ll.display()
74+
```
75+
76+
##### **1.3 Stack**
77+
**Notes**:
78+
A stack is a linear data structure that follows the **LIFO** (Last In First Out) principle. Operations are primarily **push** (add to the stack) and **pop** (remove from the stack).
79+
80+
**Code**:
81+
```python
82+
stack = []
83+
stack.append(1) # Push
84+
stack.append(2)
85+
stack.pop() # Pop (removes 2)
86+
print(stack)
87+
```
88+
89+
##### **1.4 Queue**
90+
**Notes**:
91+
A queue is a linear data structure that follows the **FIFO** (First In First Out) principle. The two main operations are **enqueue** (add to the queue) and **dequeue** (remove from the queue).
92+
93+
**Code**:
94+
```python
95+
from collections import deque
96+
queue = deque()
97+
queue.append(1) # Enqueue
98+
queue.append(2)
99+
queue.popleft() # Dequeue
100+
print(queue)
101+
```
102+
103+
##### **1.5 Hash Tables (Dictionaries in Python)**
104+
**Notes**:
105+
A hash table stores data in key-value pairs. In Python, dictionaries are implemented as hash tables, providing efficient lookups.
106+
107+
**Code**:
108+
```python
109+
hash_map = {}
110+
hash_map['key1'] = 'value1'
111+
hash_map['key2'] = 'value2'
112+
print(hash_map['key1']) # O(1) average time complexity
113+
```
114+
115+
##### **1.6 Trees**
116+
**Notes**:
117+
A tree is a hierarchical data structure with a root node and subtrees (children nodes).
118+
119+
- **Binary Tree**: A tree where each node has at most two children (left and right).
120+
121+
**Code**:
122+
```python
123+
class TreeNode:
124+
def __init__(self, data):
125+
self.data = data
126+
self.left = None
127+
self.right = None
128+
129+
class BinaryTree:
130+
def __init__(self, root):
131+
self.root = TreeNode(root)
132+
133+
def inorder_traversal(self, node):
134+
if node:
135+
self.inorder_traversal(node.left)
136+
print(node.data, end=" ")
137+
self.inorder_traversal(node.right)
138+
139+
bt = BinaryTree(1)
140+
bt.root.left = TreeNode(2)
141+
bt.root.right = TreeNode(3)
142+
bt.inorder_traversal(bt.root)
143+
```
144+
145+
##### **1.7 Graphs**
146+
**Notes**:
147+
A graph is a collection of nodes (vertices) and edges connecting them. Graphs can be **directed** or **undirected**, and **weighted** or **unweighted**.
148+
149+
**Code**:
150+
```python
151+
# Adjacency List representation
152+
graph = {
153+
'A': ['B', 'C'],
154+
'B': ['A', 'D'],
155+
'C': ['A'],
156+
'D': ['B']
157+
}
158+
```
159+
160+
---
161+
162+
#### **2. Algorithms**
163+
164+
##### **2.1 Sorting Algorithms**
165+
166+
###### **Bubble Sort**
167+
**Notes**:
168+
Bubble Sort is a simple comparison-based sorting algorithm where the largest element "bubbles up" to its correct position in each iteration.
169+
170+
**Code**:
171+
```python
172+
def bubble_sort(arr):
173+
n = len(arr)
174+
for i in range(n):
175+
for j in range(0, n-i-1):
176+
if arr[j] > arr[j+1]:
177+
arr[j], arr[j+1] = arr[j+1], arr[j]
178+
179+
arr = [64, 34, 25, 12, 22, 11, 90]
180+
bubble_sort(arr)
181+
print(arr)
182+
```
183+
184+
###### **Merge Sort**
185+
**Notes**:
186+
Merge Sort is a divide-and-conquer algorithm. It divides the array into halves, recursively sorts them, and then merges them.
187+
188+
**Code**:
189+
```python
190+
def merge_sort(arr):
191+
if len(arr) > 1:
192+
mid = len(arr) // 2
193+
left_half = arr[:mid]
194+
right_half = arr[mid:]
195+
196+
merge_sort(left_half)
197+
merge_sort(right_half)
198+
199+
i = j = k = 0
200+
201+
while i < len(left_half) and j < len(right_half):
202+
if left_half[i] < right_half[j]:
203+
arr[k] = left_half[i]
204+
i += 1
205+
else:
206+
arr[k] = right_half[j]
207+
j += 1
208+
k += 1
209+
210+
while i < len(left_half):
211+
arr[k] = left_half[i]
212+
i += 1
213+
k += 1
214+
215+
while j < len(right_half):
216+
arr[k] = right_half[j]
217+
j += 1
218+
k += 1
219+
220+
arr = [38, 27, 43, 3, 9, 82, 10]
221+
merge_sort(arr)
222+
print(arr)
223+
```
224+
225+
##### **2.2 Searching Algorithms**
226+
227+
###### **Binary Search**
228+
**Notes**:
229+
Binary Search works on sorted arrays and repeatedly divides the search interval in half.
230+
231+
**Code**:
232+
```python
233+
def binary_search(arr, x):
234+
low = 0
235+
high = len(arr) - 1
236+
while low <= high:
237+
mid = (low + high) // 2
238+
if arr[mid] == x:
239+
return mid
240+
elif arr[mid] < x:
241+
low = mid + 1
242+
else:
243+
high = mid - 1
244+
return -1
245+
246+
arr = [2, 3, 4, 10, 40]
247+
result = binary_search(arr, 10)
248+
print("Element found at index:", result)
249+
```
250+
251+
##### **2.3 Graph Algorithms**
252+
253+
###### **Depth-First Search (DFS)**
254+
**Notes**:
255+
DFS explores as far as possible along each branch before backtracking.
256+
257+
**Code**:
258+
```python
259+
def dfs(graph, node, visited=None):
260+
if visited is None:
261+
visited = set()
262+
visited.add(node)
263+
for neighbor in graph[node]:
264+
if neighbor not in visited:
265+
dfs(graph, neighbor, visited)
266+
return visited
267+
268+
graph = {
269+
'A': ['B', 'C'],
270+
'B': ['A', 'D'],
271+
'C': ['A'],
272+
'D': ['B']
273+
}
274+
print(dfs(graph, 'A'))
275+
```
276+
277+
###### **Breadth-First Search (BFS)**
278+
**Notes**:
279+
BFS explores all neighbors at the present depth level before moving on to nodes at the next depth level.
280+
281+
**Code**:
282+
```python
283+
from collections import deque
284+
285+
def bfs(graph, start):
286+
visited = set()
287+
queue = deque([start])
288+
visited.add(start)
289+
290+
while queue:
291+
vertex = queue.popleft()
292+
print(vertex, end=" ")
293+
for neighbor in graph[vertex]:
294+
if neighbor not in visited:
295+
visited.add(neighbor)
296+
queue.append(neighbor)
297+
298+
graph = {
299+
'A': ['B', 'C'],
300+
'B': ['A', 'D'],
301+
'C': ['A'],
302+
'D': ['B']
303+
}
304+
bfs(graph, 'A')
305+
```
306+
307+
---
308+
309+
### **Conclusion**
310+
Data structures and algorithms are key to optimizing and solving problems efficiently. The examples provided give a practical introduction to implementing these concepts in Python. Practice solving problems with these structures and algorithms to master them.

0 commit comments

Comments
 (0)