Skip to main content

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}