Skip to main content

rust_algorithms/sorting/
quadratic.rs

1//! O(n²) oilasidagi "o'quv" algoritmlari + Shell sort.
2//!
3//! Ular sekin, lekin *g'oyasi* keyingi hamma narsaning poydevori.
4
5/// Bubble sort — qo'shni elementlarni almashtira-almashtira "pufakchani" yuqoriga chiqarish.
6///
7/// **G'oya:** massiv bo'ylab yurib, `arr[j] > arr[j+1]` bo'lsa almashtiramiz.
8/// Bitta to'liq yurishdan keyin eng katta element **oxirida** bo'ladi.
9///
10/// Bu yerda optimallashtirilgan variant: agar bitta yurishda hech narsa almashmasa,
11/// massiv allaqachon tartiblangan — to'xtaymiz (shuning uchun eng yaxshi holat O(n)).
12///
13/// - **Time:** O(n) / O(n²) / O(n²), **Space:** O(1), **barqaror**.
14///
15/// # Misol
16/// ```
17/// use rust_algorithms::sorting::bubble_sort;
18///
19/// let mut v = vec![5, 1, 4, 2, 8];
20/// bubble_sort(&mut v);
21/// assert_eq!(v, [1, 2, 4, 5, 8]);
22/// ```
23pub fn bubble_sort<T: Ord>(arr: &mut [T]) {
24    let n = arr.len();
25    for i in 0..n {
26        let mut swapped = false;
27        // Har yurishdan keyin oxirgi `i` ta element o'z joyida — ularga tegmaymiz.
28        for j in 0..n.saturating_sub(i + 1) {
29            if arr[j] > arr[j + 1] {
30                arr.swap(j, j + 1);
31                swapped = true;
32            }
33        }
34        if !swapped {
35            break; // allaqachon tartiblangan
36        }
37    }
38}
39
40/// Selection sort — qolgan qismdan eng kichigini topib, oldinga qo'yish.
41///
42/// **G'oya:** `i` -pozitsiya uchun `i..n` oralig'idagi minimumni topamiz va almashtiramiz.
43///
44/// Almashtirishlar soni har doim **eng ko'pi bilan n ta** — yozish (write) qimmat
45/// bo'lgan xotirada (masalan, flash) shuning uchun foydali.
46///
47/// - **Time:** O(n²) har doim, **Space:** O(1), **barqaror emas**.
48///
49/// # Misol
50/// ```
51/// use rust_algorithms::sorting::selection_sort;
52///
53/// let mut v = vec![64, 25, 12, 22, 11];
54/// selection_sort(&mut v);
55/// assert_eq!(v, [11, 12, 22, 25, 64]);
56/// ```
57pub fn selection_sort<T: Ord>(arr: &mut [T]) {
58    let n = arr.len();
59    for i in 0..n {
60        let mut min_idx = i;
61        for j in (i + 1)..n {
62            if arr[j] < arr[min_idx] {
63                min_idx = j;
64            }
65        }
66        if min_idx != i {
67            arr.swap(i, min_idx);
68        }
69    }
70}
71
72/// Insertion sort — qo'lingizdagi kartalarni terganingizdek.
73///
74/// **G'oya:** chap tomon har doim tartiblangan. Navbatdagi elementni olib,
75/// chapdagi tartiblangan qismning to'g'ri joyiga "suqib" qo'yamiz.
76///
77/// **Amaliy ahamiyati katta:** kichik massivlarda (n < 32) va **deyarli tartiblangan**
78/// ma'lumotlarda hamma narsadan tez. Shuning uchun TimSort/pdqsort ichida ishlatiladi.
79///
80/// - **Time:** O(n) (tartiblangan bo'lsa) / O(n²), **Space:** O(1), **barqaror**.
81///
82/// # Misol
83/// ```
84/// use rust_algorithms::sorting::insertion_sort;
85///
86/// let mut v = vec![12, 11, 13, 5, 6];
87/// insertion_sort(&mut v);
88/// assert_eq!(v, [5, 6, 11, 12, 13]);
89/// ```
90pub fn insertion_sort<T: Ord>(arr: &mut [T]) {
91    for i in 1..arr.len() {
92        let mut j = i;
93        // Elementni o'z joyiga yetguncha chapga surib boramiz.
94        while j > 0 && arr[j - 1] > arr[j] {
95            arr.swap(j - 1, j);
96            j -= 1;
97        }
98    }
99}
100
101/// Shell sort — insertion sortning "uzoq masofaga sakraydigan" versiyasi.
102///
103/// **G'oya:** avval bir-biridan `gap` masofada turgan elementlarni tartiblaymiz,
104/// keyin `gap` ni kichraytira boramiz. Katta gaplar elementlarni tez o'z
105/// hududiga olib keladi, oxirgi `gap = 1` esa deyarli tayyor massivni tugatadi.
106///
107/// Bu yerda Knuth ketma-ketligi ishlatilgan: 1, 4, 13, 40, 121… (`3h+1`).
108///
109/// - **Time:** ~O(n^1.3) amalda, **Space:** O(1), **barqaror emas**.
110///
111/// # Misol
112/// ```
113/// use rust_algorithms::sorting::shell_sort;
114///
115/// let mut v = vec![23, 12, 1, 8, 34, 54, 2, 3];
116/// shell_sort(&mut v);
117/// assert_eq!(v, [1, 2, 3, 8, 12, 23, 34, 54]);
118/// ```
119pub fn shell_sort<T: Ord>(arr: &mut [T]) {
120    let n = arr.len();
121    if n < 2 {
122        return;
123    }
124
125    // Knuth ketma-ketligi bo'yicha eng katta gapni topamiz
126    let mut gap = 1usize;
127    while gap < n / 3 {
128        gap = gap * 3 + 1;
129    }
130
131    while gap >= 1 {
132        for i in gap..n {
133            let mut j = i;
134            while j >= gap && arr[j - gap] > arr[j] {
135                arr.swap(j - gap, j);
136                j -= gap;
137            }
138        }
139        if gap == 1 {
140            break;
141        }
142        gap /= 3;
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149    use crate::sorting::is_sorted;
150    use crate::util::Rng;
151
152    fn holatlar() -> Vec<Vec<i64>> {
153        let mut rng = Rng::new(20_26);
154        vec![
155            vec![],
156            vec![1],
157            vec![2, 1],
158            vec![1, 2, 3, 4, 5],            // tartiblangan
159            vec![5, 4, 3, 2, 1],            // teskari
160            vec![3, 3, 3, 3],               // hammasi teng
161            vec![-5, 0, 7, -2, 9, 9, -100], // manfiylar va takrorlar
162            rng.vec(200, -1000, 1000),      // tasodifiy
163        ]
164    }
165
166    fn tekshir(sort: fn(&mut [i64])) {
167        for mut v in holatlar() {
168            let mut kutilgan = v.clone();
169            kutilgan.sort_unstable();
170            sort(&mut v);
171            assert!(is_sorted(&v), "tartiblanmadi: {v:?}");
172            assert_eq!(v, kutilgan);
173        }
174    }
175
176    #[test]
177    fn bubble() {
178        tekshir(bubble_sort);
179    }
180
181    #[test]
182    fn selection() {
183        tekshir(selection_sort);
184    }
185
186    #[test]
187    fn insertion() {
188        tekshir(insertion_sort);
189    }
190
191    #[test]
192    fn shell() {
193        tekshir(shell_sort);
194    }
195
196    #[test]
197    fn bubble_barqaror() {
198        // (kalit, tartib raqami) — kalit bo'yicha saralaganda raqamlar tartibi saqlanishi kerak
199        let mut v = vec![(1, 'a'), (0, 'b'), (1, 'c'), (0, 'd')];
200        bubble_sort(&mut v);
201        assert_eq!(v, vec![(0, 'b'), (0, 'd'), (1, 'a'), (1, 'c')]);
202    }
203}