dsa/algorithms/sorting.rs
1use crate::data_structures::heap::Heap;
2
3/// Sorts a slice using the Bubble Sort algorithm.
4///
5/// The bubble sort algorithm repeatedly steps through the list, compares adjacent
6/// elements, and swaps them if they are in the wrong order. This process continues
7/// until the list is sorted.
8///
9/// # Parameters
10/// - `arr`: A mutable reference to the slice of integers to be sorted.
11///
12/// # Time Complexity
13/// - Best: `O(n)`
14/// - Worst: `O(n²)`
15/// - Average: `O(n²)`
16///
17/// # Space Complexity
18/// - `O(1)` (in-place sorting)
19///
20/// # Examples
21/// ```
22/// use dsa::algorithms::sorting::bubble_sort;
23///
24/// let mut arr = [5, 3, 8, 4, 2];
25/// bubble_sort(&mut arr);
26/// assert_eq!(arr, [2, 3, 4, 5, 8]);
27/// ```
28pub fn bubble_sort(arr: &mut [i32]) {
29 for i in 0..arr.len() {
30 for j in 1..(arr.len() - i) {
31 if arr[j] < arr[j - 1] {
32 arr.swap(j, j - 1);
33 }
34 }
35 }
36}
37
38/// Sorts a slice using the Insertion Sort algorithm.
39///
40/// Insertion sort builds the sorted array one element at a time. It takes each new element
41/// and inserts it into its correct position within the sorted portion of the array.
42///
43/// ### Parameters
44/// - `arr`: A mutable reference to the slice of integers to be sorted.
45///
46/// ### Time Complexity
47/// - Best: `O(n)`
48/// - Worst: `O(n²)`
49/// - Average: `O(n²)`
50///
51/// ### Space Complexity
52/// - `O(1)` (in-place sorting)
53///
54/// ### Examples
55/// ```
56/// use dsa::algorithms::sorting::insertion_sort;
57///
58/// let mut arr = [5, 3, 8, 4, 2];
59/// insertion_sort(&mut arr);
60/// assert_eq!(arr, [2, 3, 4, 5, 8]);
61/// ```
62pub fn insertion_sort(arr: &mut [i32]) {
63 for i in 1..arr.len() {
64 let mut j = i;
65 while j > 0 && arr[j - 1] > arr[j] {
66 arr.swap(j, j - 1);
67 j -= 1;
68 }
69 }
70}
71
72/// Sorts a slice using the Selection Sort algorithm.
73///
74/// Selection sort repeatedly selects the minimum element from the unsorted portion of the array
75/// and swaps it with the first unsorted element.
76///
77/// # Parameters
78/// - `arr`: A mutable reference to the slice of integers to be sorted.
79///
80/// # Time Complexity
81/// - Best: `O(n²)`
82/// - Worst: `O(n²)`
83/// - Average: `O(n²)`
84///
85/// # Space Complexity
86/// - `O(1)` (in-place sorting)
87///
88/// # Examples
89/// ```
90/// use dsa::algorithms::sorting::selection_sort;
91///
92/// let mut arr = [5, 3, 8, 4, 2];
93/// selection_sort(&mut arr);
94/// assert_eq!(arr, [2, 3, 4, 5, 8]);
95/// ```
96pub fn selection_sort(arr: &mut [i32]) {
97 for i in 0..arr.len() {
98 let mut min_index = i;
99 for j in i + 1..arr.len() {
100 if arr[j] < arr[min_index] {
101 min_index = j;
102 }
103 }
104 arr.swap(i, min_index);
105 }
106}
107
108/// Sorts a slice using the Merge Sort algorithm.
109///
110/// Merge sort is a divide-and-conquer algorithm that splits the array into two halves,
111/// recursively sorts them, and then merges the sorted halves.
112///
113/// # Parameters
114/// - `arr`: A mutable reference to the slice of integers to be sorted.
115///
116/// # Time Complexity
117/// - Best: `O(n log n)`
118/// - Worst: `O(n log n)`
119/// - Average: `O(n log n)`
120///
121/// # Space Complexity
122/// - `O(n)` (requires additional space for merging)
123///
124/// # Examples
125/// ```
126/// use dsa::algorithms::sorting::merge_sort;
127///
128/// let mut arr = [5, 3, 8, 4, 2];
129/// merge_sort(&mut arr);
130/// assert_eq!(arr, [2, 3, 4, 5, 8]);
131/// ```
132pub fn merge_sort(arr: &mut [i32]) {
133 if arr.len() <= 1 {
134 return;
135 }
136 let mid = arr.len() / 2;
137 merge_sort(&mut arr[..mid]);
138 merge_sort(&mut arr[mid..]);
139 merge(arr, mid);
140}
141/// Merges two sorted halves of a slice.
142///
143/// # Parameters
144/// - `arr`: The slice to merge the halves into.
145/// - `mid`: The index where the array is split into two halves.
146fn merge(arr: &mut [i32], mid: usize) {
147 let left = arr[..mid].to_vec();
148 let right = arr[mid..].to_vec();
149
150 let (mut i, mut j, mut k) = (0, 0, 0);
151
152 while i < left.len() && j < right.len() {
153 if left[i] <= right[j] {
154 arr[k] = left[i];
155 i += 1;
156 } else {
157 arr[k] = right[j];
158 j += 1;
159 }
160 k += 1;
161 }
162
163 while i < left.len() {
164 arr[k] = left[i];
165 i += 1;
166 k += 1;
167 }
168
169 while j < right.len() {
170 arr[k] = right[j];
171 j += 1;
172 k += 1;
173 }
174}
175
176/// Sorts a slice using the Quick Sort algorithm.
177///
178/// Quick Sort is a divide-and-conquer algorithm that picks a 'pivot' element from the array,
179/// partitions the array around the pivot, and recursively sorts the two subarrays.
180///
181/// # Parameters
182/// - `arr`: A mutable reference to the slice of integers to be sorted.
183///
184/// # Time Complexity
185/// - Best: `O(n log n)`
186/// - Worst: `O(n²)`
187/// - Average: `O(n log n)`
188///
189/// # Space Complexity
190/// - `O(log n)` (due to recursion stack)
191///
192/// # Examples
193/// ```
194/// use dsa::algorithms::sorting::quick_sort;
195///
196/// let mut arr = [5, 3, 8, 4, 2];
197/// quick_sort(&mut arr);
198/// assert_eq!(arr, [2, 3, 4, 5, 8]);
199/// ```
200pub fn quick_sort(arr: &mut [i32]) {
201 if arr.len() <= 1 {
202 return;
203 }
204
205 let pivot_index = partition(arr);
206
207 let (left, right) = arr.split_at_mut(pivot_index);
208 quick_sort(left);
209 quick_sort(&mut right[1..]);
210}
211/// Partitions the slice around a pivot element.
212///
213/// # Parameters
214/// - `arr`: A mutable reference to the slice to be partitioned.
215///
216/// # Returns
217/// - The index of the pivot element after partitioning.
218fn partition(arr: &mut [i32]) -> usize {
219 let pivot_index = arr.len() - 1;
220 let pivot = arr[pivot_index];
221 let mut i = 0;
222
223 for j in 0..arr.len() - 1 {
224 if arr[j] < pivot {
225 arr.swap(i, j);
226 i += 1;
227 }
228 }
229
230 arr.swap(i, pivot_index);
231 i
232}
233
234/// Sorts a slice using the Counting Sort algorithm.
235///
236/// Counting sort works by counting the occurrences of each element and then reconstructing the sorted
237/// array based on the counts.
238///
239/// # Parameters
240/// - `arr`: A mutable reference to the slice of integers to be sorted.
241///
242/// # Time Complexity
243/// - Best: `O(n + k)`
244/// - Worst: `O(n + k)`
245/// - Average: `O(n + k)`
246///
247/// # Space Complexity
248/// - `O(k)` (requires extra space for the count array)
249///
250/// # Examples
251/// ```
252/// use dsa::algorithms::sorting::counting_sort;
253///
254/// let mut arr = [5, 3, 8, 4, 2];
255/// counting_sort(&mut arr);
256/// assert_eq!(arr, [2, 3, 4, 5, 8]);
257/// ```
258pub fn counting_sort(arr: &mut [i32]) {
259 let max = *arr.iter().max().unwrap();
260 let mut count_arr = vec![0; max as usize + 1];
261
262 for &num in arr.iter() {
263 count_arr[num as usize] += 1;
264 }
265
266 let mut index = 0;
267 for (num, &count) in count_arr.iter().enumerate() {
268 for _ in 0..count {
269 arr[index] = num as i32;
270 index += 1;
271 }
272 }
273}
274
275/// Sorts a slice using the Radix Sort algorithm.
276///
277/// Radix sort processes the elements digit by digit, sorting them by each digit starting from the least significant digit.
278///
279/// # Parameters
280/// - `arr`: A mutable reference to the slice of integers to be sorted.
281///
282/// # Time Complexity
283/// - Best: `O(nk)`
284/// - Worst: `O(nk)`
285/// - Average: `O(nk)`
286///
287/// # Space Complexity
288/// - `O(n + k)` (requires additional space for the buckets)
289///
290/// # Examples
291/// ```
292/// use dsa::algorithms::sorting::radix_sort;
293///
294/// let mut arr = [170, 45, 75, 90, 802, 24, 2, 66];
295/// radix_sort(&mut arr);
296/// assert_eq!(arr, [2, 24, 45, 66, 75, 90, 170, 802]);
297/// ```
298pub fn radix_sort(arr: &mut [i32]) {
299 let max_val = *arr.iter().max().unwrap();
300 let mut exp = 1;
301
302 while max_val / exp > 0 {
303 let mut radix_array = vec![vec![]; 10];
304
305 for &num in arr.iter() {
306 let digit = (num / exp) % 10;
307 radix_array[digit as usize].push(num);
308 }
309
310 let mut idx = 0;
311 for bucket in radix_array.iter() {
312 for &num in bucket.iter() {
313 arr[idx] = num;
314 idx += 1;
315 }
316 }
317
318 exp *= 10;
319 }
320}
321
322/// Sorts a heap in ascending order (min heap) or descending order (max heap)
323///
324/// Heap sort transforms its elements into a heap, then repeatedly removes
325/// the largest (or smallest) element and places it in the correct position,
326/// restoring the heap property after each removal.
327///
328/// # Parameters
329/// - `&mut Heap<i32>`: a mutable reference to a `Heap` instance and sorts its elements
330///
331/// If the heap is configured as a max-heap, the elements
332/// will be sorted in ascending order. If it's a min-heap, the elements
333/// will be sorted in descending order.
334///
335/// # Time Complexity
336/// - Best: `O(n log n)`
337/// - Worst: `O(n log n)`
338/// - Average: `O(n log n)`
339///
340/// # Space Complexity
341/// - `O(n + k)`
342///
343/// # Examples
344/// ```
345/// use dsa::algorithms::sorting::heap_sort;
346/// use dsa::data_structures::heap::Heap;
347///
348/// let mut heap = Heap::new(false); // Min-heap
349/// heap.values = vec![3, 1, 6, 5, 2, 4];
350/// heap_sort(&mut heap);
351/// assert_eq!(heap.values, vec![6, 5, 4, 3, 2, 1]);
352/// ```
353pub fn heap_sort(heap: &mut Heap<i32>) {
354 heap.build_heap();
355 let mut considered = heap.values.len();
356
357 while considered > 1 {
358 heap.values.swap(0, considered - 1);
359 considered -= 1;
360 heap.sift_down(0, considered);
361 }
362}