Skip to content

Commit 1a03490

Browse files
authored
Merge pull request animator#584 from Ramya-korupolu/branch1
Updated sorting-algorithms.md
2 parents dcf0065 + 62205f2 commit 1a03490

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed

contrib/ds-algorithms/sorting-algorithms.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,152 @@ print("Sorted array:", arr) # Output: [3, 9, 10, 27, 38, 43, 82]
316316
### Complexity Analysis
317317
- **Time Complexity**: `O(n log n)` for all cases. Merge sort always divides the list into halves until each sublist contains only one element, and then merges them back together, resulting in O(n log n) time complexity.
318318
- **Space Complexity**: `O(n)` auxiliary space. In the iterative version, merge sort uses additional space for creating temporary sublists during merging operations.
319+
320+
## 5. Insertion Sort
321+
322+
Insertion sort is a straightforward and efficient sorting algorithm for small datasets. It builds the final sorted array one element at a time. It is much like sorting playing cards in your hands: you take one card at a time and insert it into its correct position among the already sorted cards.
323+
324+
**Algorithm Overview:**
325+
- **Start from the Second Element:** Begin with the second element, assuming the first element is already sorted.
326+
- **Compare with Sorted Subarray:** Take the current element and compare it with elements in the sorted subarray (the part of the array before the current element).
327+
- **Insert in Correct Position:** Shift all elements in the sorted subarray that are greater than the current element to one position ahead. Insert the current element into its correct position.
328+
- **Repeat Until End:** Repeat this process for all elements in the array.
329+
330+
### Example with Visualization
331+
Let's sort the list `[5, 3, 8, 1, 2]` using insertion sort.
332+
333+
**Step-by-Step Visualization:**
334+
**Initial List:** `[5, 3, 8, 1, 2]`
335+
336+
1. **Pass 1:**
337+
- Current element: 3
338+
- Compare 3 with 5, move 5 to the right: `[5, 5, 8, 1, 2]`
339+
- Insert 3 in its correct position: `[3, 5, 8, 1, 2]`
340+
341+
2. **Pass 2:**
342+
- Current element: 8
343+
- 8 is already in the correct position: `[3, 5, 8, 1, 2]`
344+
345+
3. **Pass 3:**
346+
- Current element: 1
347+
- Compare 1 with 8, move 8 to the right: `[3, 5, 8, 8, 2]`
348+
- Compare 1 with 5, move 5 to the right: `[3, 5, 5, 8, 2]`
349+
- Compare 1 with 3, move 3 to the right: `[3, 3, 5, 8, 2]`
350+
- Insert 1 in its correct position: `[1, 3, 5, 8, 2]`
351+
352+
4. **Pass 4:**
353+
- Current element: 2
354+
- Compare 2 with 8, move 8 to the right: `[1, 3, 5, 8, 8]`
355+
- Compare 2 with 5, move 5 to the right: `[1, 3, 5, 5, 8]`
356+
- Compare 2 with 3, move 3 to the right: `[1, 3, 3, 5, 8]`
357+
- Insert 2 in its correct position: `[1, 2, 3, 5, 8]`
358+
359+
### Insertion Sort Code in Python
360+
361+
362+
```python
363+
364+
def insertion_sort(arr):
365+
# Traverse from 1 to len(arr)
366+
for i in range(1, len(arr)):
367+
key = arr[i]
368+
# Move elements of arr[0..i-1], that are greater than key,
369+
# to one position ahead of their current position
370+
j = i - 1
371+
while j >= 0 and key < arr[j]:
372+
arr[j + 1] = arr[j]
373+
j -= 1
374+
arr[j + 1] = key
375+
376+
# Example usage
377+
arr = [5, 3, 8, 1, 2]
378+
insertion_sort(arr)
379+
print("Sorted array:", arr) # Output: [1, 2, 3, 5, 8]
380+
```
381+
382+
### Complexity Analysis
383+
- **Worst Case:** `𝑂(𝑛^2)` comparisons and swaps. This occurs when the array is in reverse order.
384+
- **Best Case:** `𝑂(𝑛)` comparisons and `𝑂(1)` swaps. This happens when the array is already sorted.
385+
- **Average Case:** `𝑂(𝑛^2)` comparisons and swaps. This is the expected number of comparisons and swaps over all possible input sequences.
386+
387+
## 6. Heap Sort
388+
389+
Heap Sort is an efficient comparison-based sorting algorithm that uses a binary heap data structure. It divides its input into a sorted and an unsorted region and iteratively shrinks the unsorted region by extracting the largest (or smallest) element and moving it to the sorted region.
390+
391+
**Algorithm Overview:**
392+
- **Build a Max Heap:** Convert the array into a max heap, a complete binary tree where the value of each node is greater than or equal to the values of its children.
393+
- **Heapify:** Ensure that the subtree rooted at each node satisfies the max heap property. This process is called heapify.
394+
- **Extract Maximum:** Swap the root (the maximum element) with the last element of the heap and reduce the heap size by one. Restore the max heap property by heapifying the root.
395+
- **Repeat:** Continue extracting the maximum element and heapifying until the entire array is sorted.
396+
397+
### Example with Visualization
398+
399+
Let's sort the list `[5, 3, 8, 1, 2]` using heap sort.
400+
401+
1. **Build Max Heap:**
402+
- Initial array: `[5, 3, 8, 1, 2]`
403+
- Start heapifying from the last non-leaf node.
404+
- Heapify at index 1: `[5, 3, 8, 1, 2]` (no change, children are already less than the parent)
405+
- Heapify at index 0: `[8, 3, 5, 1, 2]` (swap 5 and 8 to make 8 the root)
406+
407+
2. **Heapify Process:**
408+
- Heapify at index 0: `[8, 3, 5, 1, 2]` (no change needed, already a max heap)
409+
410+
3. **Extract Maximum:**
411+
- Swap root with the last element: `[2, 3, 5, 1, 8]`
412+
- Heapify at index 0: `[5, 3, 2, 1, 8]` (swap 2 and 5)
413+
414+
4. **Repeat Extraction:**
415+
- Swap root with the second last element: `[1, 3, 2, 5, 8]`
416+
- Heapify at index 0: `[3, 1, 2, 5, 8]` (swap 1 and 3)
417+
- Swap root with the third last element: `[2, 1, 3, 5, 8]`
418+
- Heapify at index 0: `[2, 1, 3, 5, 8]` (no change needed)
419+
- Swap root with the fourth last element: `[1, 2, 3, 5, 8]`
420+
421+
After all extractions, the array is sorted: `[1, 2, 3, 5, 8]`.
422+
423+
### Heap Sort Code in Python
424+
425+
```python
426+
def heapify(arr, n, i):
427+
largest = i # Initialize largest as root
428+
left = 2 * i + 1 # left child index
429+
right = 2 * i + 2 # right child index
430+
431+
# See if left child of root exists and is greater than root
432+
if left < n and arr[largest] < arr[left]:
433+
largest = left
434+
435+
# See if right child of root exists and is greater than root
436+
if right < n and arr[largest] < arr[right]:
437+
largest = right
438+
439+
# Change root, if needed
440+
if largest != i:
441+
arr[i], arr[largest] = arr[largest], arr[i] # swap
442+
443+
# Heapify the root.
444+
heapify(arr, n, largest)
445+
446+
def heap_sort(arr):
447+
n = len(arr)
448+
449+
# Build a maxheap.
450+
for i in range(n // 2 - 1, -1, -1):
451+
heapify(arr, n, i)
452+
453+
# One by one extract elements
454+
for i in range(n - 1, 0, -1):
455+
arr[i], arr[0] = arr[0], arr[i] # swap
456+
heapify(arr, i, 0)
457+
458+
# Example usage
459+
arr = [5, 3, 8, 1, 2]
460+
heap_sort(arr)
461+
print("Sorted array:", arr) # Output: [1, 2, 3, 5, 8]
462+
```
463+
464+
### Complexity Analysis
465+
- **Worst Case:** `𝑂(𝑛log𝑛)`. Building the heap takes `𝑂(𝑛)` time, and each of the 𝑛 element extractions takes `𝑂(log𝑛)` time.
466+
- **Best Case:** `𝑂(𝑛log𝑛)`. Even if the array is already sorted, heap sort will still build the heap and perform the extractions.
467+
- **Average Case:** `𝑂(𝑛log𝑛)`. Similar to the worst-case, the overall complexity remains `𝑂(𝑛log𝑛)` because each insertion and deletion in a heap takes `𝑂(log𝑛)` time, and these operations are performed 𝑛 times.

0 commit comments

Comments
 (0)