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}