Skip to main content

rust_algorithms/sorting/
linear_time.rs

1//! Taqqoslashsiz (non-comparison) tartiblash: counting, radix, bucket.
2//!
3//! ## "n log n dan tez bo'lishi mumkinmi?"
4//!
5//! **Taqqoslashga asoslangan** har qanday algoritm uchun Ω(n log n) — buzib bo'lmaydigan
6//! nazariy chegara (isbot: n! ta turli natija bor, har taqqoslash 1 bit ma'lumot beradi,
7//! log₂(n!) ≈ n log n).
8//!
9//! Lekin biz elementlarni **taqqoslamasak**, balki ularning *qiymatini* to'g'ridan-to'g'ri
10//! indeks sifatida ishlatsak — chegara ishlamaydi. Shu yerdagi uchta algoritm shunday qiladi.
11
12/// Counting sort — qiymatlarni sanab, o'z joyiga qo'yish.
13///
14/// **G'oya:** har bir qiymat necha marta uchraganini sanaymiz, keyin prefiks yig'indi
15/// orqali har bir qiymatning yakuniy o'rnini aniqlaymiz.
16///
17/// - **Shart:** qiymatlar butun va **tor oraliqda** bo'lishi kerak.
18/// - **Time:** O(n + k), **Space:** O(n + k), bu yerda `k = max - min + 1`.
19/// - **Barqaror:** ha (teskari yurish tufayli).
20///
21/// > Diqqat: `k` juda katta bo'lsa (masalan, `i32::MIN..i32::MAX`), bu algoritm
22/// > gigabaytlab xotira so'raydi. Shuning uchun oraliq 10 milliondan katta bo'lsa
23/// > funksiya `false` qaytaradi va massivga tegmaydi.
24///
25/// # Misol
26/// ```
27/// use rust_algorithms::sorting::counting_sort;
28///
29/// let mut v = vec![4, 2, 2, 8, 3, 3, 1];
30/// assert!(counting_sort(&mut v));
31/// assert_eq!(v, [1, 2, 2, 3, 3, 4, 8]);
32/// ```
33pub fn counting_sort(arr: &mut [i32]) -> bool {
34    const MAX_ORALIQ: i64 = 10_000_000;
35
36    if arr.len() < 2 {
37        return true;
38    }
39    let min = *arr.iter().min().unwrap() as i64;
40    let max = *arr.iter().max().unwrap() as i64;
41    let k = max - min + 1;
42    if k > MAX_ORALIQ {
43        return false; // oraliq juda katta — merge/quick sort ishlating
44    }
45
46    // 1) sanaymiz
47    let mut count = vec![0usize; k as usize];
48    for &x in arr.iter() {
49        count[(x as i64 - min) as usize] += 1;
50    }
51
52    // 2) prefiks yig'indi: count[i] = shu qiymatgacha bo'lgan elementlar soni
53    for i in 1..count.len() {
54        count[i] += count[i - 1];
55    }
56
57    // 3) oxiridan boshiga yurib joylashtiramiz — bu barqarorlikni saqlaydi
58    let mut out = vec![0i32; arr.len()];
59    for &x in arr.iter().rev() {
60        let idx = (x as i64 - min) as usize;
61        count[idx] -= 1;
62        out[count[idx]] = x;
63    }
64
65    arr.copy_from_slice(&out);
66    true
67}
68
69/// Radix sort (LSD, 256 lik asos) — sonlarni **raqamma-raqam** tartiblash.
70///
71/// **G'oya:** eng past baytdan boshlab, har bir bayt bo'yicha counting sort qilamiz.
72/// Counting sort barqaror bo'lgani uchun oldingi bosqichlar natijasi buzilmaydi —
73/// 8 ta bosqichdan keyin butun `u64` tartiblangan bo'ladi.
74///
75/// - **Time:** O(d·(n + b)) = `u64` uchun 8·(n + 256) ≈ **O(n)**.
76/// - **Space:** O(n + b), **barqaror**.
77///
78/// Millionlab butun sonlarni tartiblashda `sort_unstable` dan ham tez bo'lishi mumkin.
79///
80/// # Misol
81/// ```
82/// use rust_algorithms::sorting::radix_sort;
83///
84/// let mut v: Vec<u64> = vec![170, 45, 75, 90, 802, 24, 2, 66];
85/// radix_sort(&mut v);
86/// assert_eq!(v, [2, 24, 45, 66, 75, 90, 170, 802]);
87/// ```
88///
89/// **Manfiy sonlar-chi?** `i64` ni `(x as i64 ^ i64::MIN) as u64` ko'rinishida
90/// almashtirsangiz (belgi bitini teskari qilib), tartib saqlanadi.
91pub fn radix_sort(arr: &mut [u64]) {
92    if arr.len() < 2 {
93        return;
94    }
95    let n = arr.len();
96    let mut buf = vec![0u64; n];
97
98    for bayt in 0..8 {
99        let siljish = bayt * 8;
100
101        // shu bayt bo'yicha sanaymiz
102        let mut count = [0usize; 256];
103        for &x in arr.iter() {
104            count[((x >> siljish) & 0xFF) as usize] += 1;
105        }
106
107        // bu baytda hamma bir xilmi? unda bosqichni o'tkazib yuboramiz
108        if count.contains(&n) {
109            continue;
110        }
111
112        // prefiks yig'indi
113        let mut sum = 0usize;
114        for c in count.iter_mut() {
115            let hozirgi = *c;
116            *c = sum;
117            sum += hozirgi;
118        }
119
120        // barqaror joylashtirish
121        for &x in arr.iter() {
122            let idx = ((x >> siljish) & 0xFF) as usize;
123            buf[count[idx]] = x;
124            count[idx] += 1;
125        }
126        arr.copy_from_slice(&buf);
127    }
128}
129
130/// Bucket sort — qiymatlarni "chelaklarga" taqsimlab, har birini alohida tartiblash.
131///
132/// **G'oya:** qiymatlar oralig'ini `n` ta teng bo'lakka bo'lamiz. Har bir element
133/// o'z chelagiga tushadi; chelaklar ichi insertion sort bilan tartiblanadi;
134/// oxirida chelaklar ketma-ket birlashtiriladi.
135///
136/// - **Time:** O(n + k) — qiymatlar **tekis taqsimlangan** bo'lsa; eng yomon holatda O(n²)
137///   (hamma element bitta chelakka tushsa).
138/// - **Space:** O(n), **barqaror**.
139///
140/// # Misol
141/// ```
142/// use rust_algorithms::sorting::bucket_sort;
143///
144/// let mut v = vec![0.42, 0.32, 0.75, 0.12, 0.99, 0.51];
145/// bucket_sort(&mut v);
146/// assert_eq!(v, [0.12, 0.32, 0.42, 0.51, 0.75, 0.99]);
147/// ```
148pub fn bucket_sort(arr: &mut [f64]) {
149    let n = arr.len();
150    if n < 2 {
151        return;
152    }
153
154    let min = arr.iter().cloned().fold(f64::INFINITY, f64::min);
155    let max = arr.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
156    if !min.is_finite() || !max.is_finite() || min == max {
157        // NaN/cheksizlik yoki hamma qiymat teng — oddiy yo'l bilan tartiblaymiz
158        arr.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
159        return;
160    }
161
162    let mut chelaklar: Vec<Vec<f64>> = vec![Vec::new(); n];
163    let kenglik = (max - min) / n as f64;
164    for &x in arr.iter() {
165        let mut idx = ((x - min) / kenglik) as usize;
166        if idx >= n {
167            idx = n - 1; // maksimal qiymat uchun
168        }
169        chelaklar[idx].push(x);
170    }
171
172    let mut k = 0usize;
173    for chelak in chelaklar.iter_mut() {
174        chelak.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
175        for &x in chelak.iter() {
176            arr[k] = x;
177            k += 1;
178        }
179    }
180}
181
182#[cfg(test)]
183mod tests {
184    use super::*;
185    use crate::sorting::is_sorted;
186    use crate::util::Rng;
187
188    #[test]
189    fn counting_ishlaydi() {
190        let mut rng = Rng::new(11);
191        for _ in 0..20 {
192            let mut v: Vec<i32> = rng
193                .vec(300, -50, 50)
194                .into_iter()
195                .map(|x| x as i32)
196                .collect();
197            let mut kutilgan = v.clone();
198            kutilgan.sort_unstable();
199            assert!(counting_sort(&mut v));
200            assert_eq!(v, kutilgan);
201        }
202        let mut bosh: Vec<i32> = vec![];
203        assert!(counting_sort(&mut bosh));
204    }
205
206    #[test]
207    fn counting_juda_katta_oraliqda_rad_etadi() {
208        let mut v = vec![i32::MIN, 0, i32::MAX];
209        assert!(!counting_sort(&mut v));
210        assert_eq!(v, vec![i32::MIN, 0, i32::MAX]); // massivga tegilmagan
211    }
212
213    #[test]
214    fn radix_ishlaydi() {
215        let mut rng = Rng::new(22);
216        for n in [0usize, 1, 2, 500] {
217            let mut v: Vec<u64> = (0..n).map(|_| rng.next_u64() % 1_000_000).collect();
218            let mut kutilgan = v.clone();
219            kutilgan.sort_unstable();
220            radix_sort(&mut v);
221            assert_eq!(v, kutilgan);
222        }
223    }
224
225    #[test]
226    fn radix_katta_sonlarda() {
227        let mut rng = Rng::new(33);
228        let mut v: Vec<u64> = (0..2000).map(|_| rng.next_u64()).collect();
229        let mut kutilgan = v.clone();
230        kutilgan.sort_unstable();
231        radix_sort(&mut v);
232        assert_eq!(v, kutilgan);
233    }
234
235    #[test]
236    fn bucket_ishlaydi() {
237        let mut rng = Rng::new(44);
238        let mut v: Vec<f64> = (0..500)
239            .map(|_| rng.next_u64() as f64 / u64::MAX as f64)
240            .collect();
241        bucket_sort(&mut v);
242        assert!(v.windows(2).all(|w| w[0] <= w[1]));
243
244        let mut teng = vec![1.5; 10];
245        bucket_sort(&mut teng);
246        assert_eq!(teng, vec![1.5; 10]);
247
248        let mut kichik = vec![2.0];
249        bucket_sort(&mut kichik);
250        assert_eq!(kichik, vec![2.0]);
251    }
252
253    #[test]
254    fn hammasi_bir_xil_natija_beradi() {
255        let mut rng = Rng::new(55);
256        let asl: Vec<i32> = rng.vec(400, 0, 999).into_iter().map(|x| x as i32).collect();
257
258        let mut a = asl.clone();
259        assert!(counting_sort(&mut a));
260
261        let mut b: Vec<u64> = asl.iter().map(|&x| x as u64).collect();
262        radix_sort(&mut b);
263
264        assert!(is_sorted(&a));
265        assert_eq!(a.iter().map(|&x| x as u64).collect::<Vec<_>>(), b);
266    }
267}