rust_algorithms/sorting/efficient.rs
1//! O(n log n) — "kattalar ligasi": merge, quick, heap sort.
2
3/// Merge sort — "bo'l va hukmronlik qil" (divide & conquer) ning etaloni.
4///
5/// **G'oya (3 qadam):**
6/// 1. Massivni ikkiga bo'lamiz;
7/// 2. Har ikkala yarmini **rekursiv** tartiblaymiz;
8/// 3. Ikki tartiblangan yarmni bitta tartiblangan massivga **qo'shamiz** (merge).
9///
10/// Merge qadami chiziqli: ikkala yarmning boshiga barmoq qo'yib, kichigini olaveramiz.
11///
12/// - **Time:** O(n log n) — har doim (kirishga bog'liq emas).
13/// - **Space:** O(n) — vaqtinchalik bufer.
14/// - **Barqaror:** ha (`<=` sharti tufayli chapdagi element birinchi olinadi).
15///
16/// # Misol
17/// ```
18/// use rust_algorithms::sorting::merge_sort;
19///
20/// let mut v = vec![38, 27, 43, 3, 9, 82, 10];
21/// merge_sort(&mut v);
22/// assert_eq!(v, [3, 9, 10, 27, 38, 43, 82]);
23/// ```
24pub fn merge_sort<T: Ord + Clone>(arr: &mut [T]) {
25 let n = arr.len();
26 if n <= 1 {
27 return;
28 }
29 // Buferni bir marta ajratamiz (har rekursiyada emas) — bu tezlik uchun muhim.
30 let mut buf = arr.to_vec();
31 merge_sort_rec(arr, &mut buf);
32}
33
34fn merge_sort_rec<T: Ord + Clone>(arr: &mut [T], buf: &mut [T]) {
35 let n = arr.len();
36 if n <= 1 {
37 return;
38 }
39 let mid = n / 2;
40 {
41 let (left, right) = arr.split_at_mut(mid);
42 let (bl, br) = buf.split_at_mut(mid);
43 merge_sort_rec(left, bl);
44 merge_sort_rec(right, br);
45 }
46 // Ikki tartiblangan yarmni buferga qo'shamiz, so'ng qaytarib ko'chiramiz.
47 merge(&arr[..mid], &arr[mid..], buf);
48 arr.clone_from_slice(&buf[..n]);
49}
50
51/// Ikki tartiblangan slicedan bitta tartiblangan ketma-ketlik yasaydi.
52fn merge<T: Ord + Clone>(left: &[T], right: &[T], out: &mut [T]) {
53 let (mut i, mut j, mut k) = (0, 0, 0);
54 while i < left.len() && j < right.len() {
55 // `<=` — barqarorlikning kaliti: tenglikda chapdagini olamiz.
56 if left[i] <= right[j] {
57 out[k] = left[i].clone();
58 i += 1;
59 } else {
60 out[k] = right[j].clone();
61 j += 1;
62 }
63 k += 1;
64 }
65 while i < left.len() {
66 out[k] = left[i].clone();
67 i += 1;
68 k += 1;
69 }
70 while j < right.len() {
71 out[k] = right[j].clone();
72 j += 1;
73 k += 1;
74 }
75}
76
77/// Quick sort — amaliyotdagi eng tez umumiy tartiblash algoritmi.
78///
79/// **G'oya:** pivot (tayanch element) tanlaymiz va massivni ikkiga ajratamiz:
80/// pivotdan kichiklar chapga, kattalar o'ngga. Pivot o'z **yakuniy** joyiga tushadi.
81/// Keyin chap va o'ng qismlarni rekursiv tartiblaymiz.
82///
83/// Bu implementatsiyada ikkita muhim optimallashtirish bor:
84/// - **median-of-three** pivot: tartiblangan massivda O(n²) ga tushib qolmaslik uchun;
85/// - kichik bo'laklar (< 16) uchun **insertion sort**.
86///
87/// - **Time:** O(n log n) o'rtacha, O(n²) nazariy eng yomon holatda.
88/// - **Space:** O(log n) — rekursiya stacki. **Barqaror emas.**
89///
90/// # Misol
91/// ```
92/// use rust_algorithms::sorting::quick_sort;
93///
94/// let mut v = vec![10, 7, 8, 9, 1, 5];
95/// quick_sort(&mut v);
96/// assert_eq!(v, [1, 5, 7, 8, 9, 10]);
97/// ```
98pub fn quick_sort<T: Ord>(arr: &mut [T]) {
99 const KICHIK: usize = 16;
100
101 if arr.len() <= 1 {
102 return;
103 }
104 if arr.len() <= KICHIK {
105 super::insertion_sort(arr);
106 return;
107 }
108
109 let p = partition(arr);
110 let (left, right) = arr.split_at_mut(p);
111 quick_sort(left);
112 quick_sort(&mut right[1..]); // right[0] — pivot, u allaqachon o'z joyida
113}
114
115/// Lomuto bo'lish sxemasi. Qaytadi: pivotning yakuniy indeksi.
116fn partition<T: Ord>(arr: &mut [T]) -> usize {
117 let last = arr.len() - 1;
118 let pivot_idx = median_of_three(arr);
119 arr.swap(pivot_idx, last); // pivotni vaqtincha oxirga olamiz
120
121 let mut store = 0;
122 for i in 0..last {
123 if arr[i] <= arr[last] {
124 arr.swap(i, store);
125 store += 1;
126 }
127 }
128 arr.swap(store, last); // pivotni o'z joyiga qaytaramiz
129 store
130}
131
132/// Birinchi, o'rta va oxirgi elementlarning **medianasi** indeksini qaytaradi.
133/// Bu allaqachon tartiblangan kirishlarda quick sortni O(n²) dan saqlaydi.
134fn median_of_three<T: Ord>(arr: &[T]) -> usize {
135 let (a, b, c) = (0, arr.len() / 2, arr.len() - 1);
136 if arr[a] < arr[b] {
137 if arr[b] < arr[c] {
138 b
139 } else if arr[a] < arr[c] {
140 c
141 } else {
142 a
143 }
144 } else if arr[a] < arr[c] {
145 a
146 } else if arr[b] < arr[c] {
147 c
148 } else {
149 b
150 }
151}
152
153/// Heap sort — max-heap (uyum) yordamida tartiblash.
154///
155/// **G'oya (2 bosqich):**
156/// 1. Massivni max-heapga aylantiramiz (`build_heap`, O(n));
157/// 2. n marta: ildizdagi (eng katta) elementni oxirgi element bilan almashtiramiz,
158/// heap hajmini bittaga kamaytiramiz va ildizni `sift_down` bilan joyiga tushiramiz.
159///
160/// **Kuchli tomoni:** qo'shimcha xotira **umuman kerak emas**, va eng yomon holat ham
161/// kafolatlangan O(n log n) (quick sortdan farqli).
162/// **Zaif tomoni:** keshga do'st emas — shuning uchun amalda quick sortdan sekinroq.
163///
164/// - **Time:** O(n log n) har doim, **Space:** O(1), **barqaror emas**.
165///
166/// # Misol
167/// ```
168/// use rust_algorithms::sorting::heap_sort;
169///
170/// let mut v = vec![12, 11, 13, 5, 6, 7];
171/// heap_sort(&mut v);
172/// assert_eq!(v, [5, 6, 7, 11, 12, 13]);
173/// ```
174pub fn heap_sort<T: Ord>(arr: &mut [T]) {
175 let n = arr.len();
176 if n < 2 {
177 return;
178 }
179
180 // 1) max-heap quramiz: oxirgi ota-tugundan boshlab yuqoriga
181 for i in (0..n / 2).rev() {
182 sift_down(arr, i, n);
183 }
184
185 // 2) maksimumni oxirga chiqarib boramiz
186 for end in (1..n).rev() {
187 arr.swap(0, end);
188 sift_down(arr, 0, end);
189 }
190}
191
192/// `root` dagi elementni `len` chegarasidagi heap ichida to'g'ri joyiga tushiradi.
193fn sift_down<T: Ord>(arr: &mut [T], root: usize, len: usize) {
194 let mut root = root;
195 loop {
196 let left = 2 * root + 1;
197 if left >= len {
198 break;
199 }
200 let right = left + 1;
201 // ikki farzanddan kattasini tanlaymiz
202 let mut largest = left;
203 if right < len && arr[right] > arr[left] {
204 largest = right;
205 }
206 if arr[root] >= arr[largest] {
207 break; // heap sharti bajarildi
208 }
209 arr.swap(root, largest);
210 root = largest;
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217 use crate::sorting::is_sorted;
218 use crate::util::Rng;
219
220 fn holatlar() -> Vec<Vec<i64>> {
221 let mut rng = Rng::new(777);
222 vec![
223 vec![],
224 vec![1],
225 vec![2, 1],
226 (0..100).collect(),
227 (0..100).rev().collect(),
228 vec![7; 64],
229 rng.vec(1000, -10_000, 10_000),
230 rng.vec(257, 0, 3), // ko'p takrorlanuvchi qiymatlar
231 ]
232 }
233
234 fn tekshir(sort: fn(&mut [i64])) {
235 for mut v in holatlar() {
236 let mut kutilgan = v.clone();
237 kutilgan.sort_unstable();
238 sort(&mut v);
239 assert!(is_sorted(&v));
240 assert_eq!(v, kutilgan);
241 }
242 }
243
244 #[test]
245 fn merge() {
246 tekshir(merge_sort);
247 }
248
249 #[test]
250 fn quick() {
251 tekshir(quick_sort);
252 }
253
254 #[test]
255 fn heap() {
256 tekshir(heap_sort);
257 }
258
259 #[test]
260 fn merge_barqaror() {
261 let mut v = vec![(2, 'a'), (1, 'b'), (2, 'c'), (1, 'd'), (2, 'e')];
262 merge_sort(&mut v);
263 assert_eq!(v, vec![(1, 'b'), (1, 'd'), (2, 'a'), (2, 'c'), (2, 'e')]);
264 }
265
266 #[test]
267 fn quick_tartiblangan_kirishda_ham_tez() {
268 // median-of-three tufayli 100k tartiblangan element muammosiz o'tadi
269 let mut v: Vec<i64> = (0..100_000).collect();
270 quick_sort(&mut v);
271 assert!(is_sorted(&v));
272 }
273
274 #[test]
275 fn satrlarni_ham_tartiblaydi() {
276 let mut v = vec!["olma", "anor", "banan", "uzum"];
277 merge_sort(&mut v);
278 assert_eq!(v, ["anor", "banan", "olma", "uzum"]);
279 }
280}