Skip to main content

rust_algorithms/searching/
advanced.rs

1//! Qo'shimcha qidiruv algoritmlari: jump, interpolation, exponential, ternary.
2
3/// Jump search — tartiblangan massivda √n qadamlab "sakrab" qidirish.
4///
5/// **G'oya:** har `√n` qadamda bir marta qaraymiz; `target` dan katta blok topilsa,
6/// shu blok ichida linear search qilamiz.
7///
8/// **Nega kerak?** Disk/lentaga o'xshash, "orqaga qaytish qimmat" bo'lgan
9/// muhitlarda binary searchdan ko'ra kamroq sakrash qiladi.
10///
11/// - **Time:** O(√n), **Space:** O(1). Shart: tartiblangan bo'lishi.
12///
13/// # Misol
14/// ```
15/// use rust_algorithms::searching::jump_search;
16///
17/// let v: Vec<i32> = (0..100).collect();
18/// assert_eq!(jump_search(&v, &73), Some(73));
19/// assert_eq!(jump_search(&v, &1000), None);
20/// ```
21pub fn jump_search<T: Ord>(list: &[T], target: &T) -> Option<usize> {
22    let n = list.len();
23    if n == 0 {
24        return None;
25    }
26    let step = (n as f64).sqrt().ceil() as usize;
27    let step = step.max(1);
28
29    // 1) target bo'lishi mumkin bo'lgan blokni topamiz
30    let mut block_start = 0usize;
31    while block_start < n && list[(block_start + step - 1).min(n - 1)] < *target {
32        block_start += step;
33    }
34    if block_start >= n {
35        return None;
36    }
37
38    // 2) blok ichida linear search
39    let block_end = (block_start + step).min(n);
40    (block_start..block_end).find(|&i| list[i] == *target)
41}
42
43/// Interpolation search — qiymatlar **tekis taqsimlangan** bo'lsa binary searchdan tez.
44///
45/// **G'oya:** o'rtaga emas, qiymatga qarab "taxmin qilingan" joyga sakraymiz —
46/// lug'atdan "Zokir" so'zini oxiridan qidirganingizdek.
47///
48/// - **Time:** o'rtacha O(log log n), eng yomon holatda O(n) (masalan, 1,2,4,8,…,2^k).
49/// - **Space:** O(1). Shart: tartiblangan `i64` slice.
50///
51/// # Misol
52/// ```
53/// use rust_algorithms::searching::interpolation_search;
54///
55/// let v: Vec<i64> = (0..1000).map(|x| x * 2).collect();
56/// assert_eq!(interpolation_search(&v, 400), Some(200));
57/// assert_eq!(interpolation_search(&v, 401), None);
58/// ```
59pub fn interpolation_search(list: &[i64], target: i64) -> Option<usize> {
60    if list.is_empty() {
61        return None;
62    }
63    let (mut lo, mut hi) = (0usize, list.len() - 1);
64
65    while lo <= hi && target >= list[lo] && target <= list[hi] {
66        if list[hi] == list[lo] {
67            return if list[lo] == target { Some(lo) } else { None };
68        }
69        // chiziqli interpolyatsiya: qiymat oralig'idagi nisbatni indekslarga ko'chiramiz
70        let span = (list[hi] - list[lo]) as i128;
71        let offset = ((target - list[lo]) as i128 * (hi - lo) as i128) / span;
72        let pos = lo + offset as usize;
73
74        match list[pos].cmp(&target) {
75            std::cmp::Ordering::Equal => return Some(pos),
76            std::cmp::Ordering::Less => lo = pos + 1,
77            std::cmp::Ordering::Greater => {
78                if pos == 0 {
79                    return None;
80                }
81                hi = pos - 1;
82            }
83        }
84    }
85    None
86}
87
88/// Exponential search — avval oraliqni 1, 2, 4, 8… deb kengaytirib topadi,
89/// so'ng shu oraliqda binary search qiladi.
90///
91/// **Qachon kerak:** massiv juda katta (yoki uzunligi noma'lum) va qidirilayotgan
92/// element **boshiga yaqin** bo'lsa. `i` — javob indeksi bo'lsa, narxi O(log i).
93///
94/// - **Time:** O(log i), **Space:** O(1). Shart: tartiblangan.
95///
96/// # Misol
97/// ```
98/// use rust_algorithms::searching::exponential_search;
99///
100/// let v: Vec<i32> = (0..1_000_000).collect();
101/// assert_eq!(exponential_search(&v, &5), Some(5)); // deyarli bir zumda
102/// ```
103pub fn exponential_search<T: Ord>(list: &[T], target: &T) -> Option<usize> {
104    let n = list.len();
105    if n == 0 {
106        return None;
107    }
108    if list[0] == *target {
109        return Some(0);
110    }
111
112    let mut bound = 1usize;
113    while bound < n && list[bound] < *target {
114        bound *= 2;
115    }
116    let lo = bound / 2;
117    let hi = (bound + 1).min(n);
118
119    // [lo, hi) oralig'ida binary search
120    super::binary_search(&list[lo..hi], target).map(|i| i + lo)
121}
122
123/// Ternary search — **unimodal** (avval o'sib, keyin kamayadigan) funksiya maksimumi.
124///
125/// **G'oya:** oraliqni har qadamda uchga bo'lib, maksimum bo'lishi mumkin bo'lmagan
126/// uchdan birini tashlab yuboramiz.
127///
128/// `eps` — kerakli aniqlik. Qaytadi: maksimum bo'lgan `x`.
129///
130/// - **Time:** O(log((hi-lo)/eps)), **Space:** O(1).
131///
132/// # Misol
133/// ```
134/// use rust_algorithms::searching::ternary_search_max;
135///
136/// // f(x) = -(x-3)^2 + 10 → maksimum x = 3 da
137/// let x = ternary_search_max(-10.0, 10.0, 1e-9, |x| -(x - 3.0) * (x - 3.0) + 10.0);
138/// assert!((x - 3.0).abs() < 1e-5);
139/// ```
140pub fn ternary_search_max<F: Fn(f64) -> f64>(lo: f64, hi: f64, eps: f64, f: F) -> f64 {
141    let (mut lo, mut hi) = (lo, hi);
142    while hi - lo > eps {
143        let m1 = lo + (hi - lo) / 3.0;
144        let m2 = hi - (hi - lo) / 3.0;
145        if f(m1) < f(m2) {
146            lo = m1;
147        } else {
148            hi = m2;
149        }
150    }
151    (lo + hi) / 2.0
152}
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157
158    #[test]
159    fn jump_hamma_elementni_topadi() {
160        let v: Vec<i32> = (0..200).map(|x| x * 5).collect();
161        for (i, x) in v.iter().enumerate() {
162            assert_eq!(jump_search(&v, x), Some(i), "x = {x}");
163        }
164        assert_eq!(jump_search(&v, &3), None);
165        assert_eq!(jump_search::<i32>(&[], &1), None);
166    }
167
168    #[test]
169    fn interpolation_hamma_elementni_topadi() {
170        let v: Vec<i64> = (0..500).map(|x| x * 3 + 7).collect();
171        for (i, &x) in v.iter().enumerate() {
172            assert_eq!(interpolation_search(&v, x), Some(i), "x = {x}");
173        }
174        assert_eq!(interpolation_search(&v, 8), None);
175        assert_eq!(interpolation_search(&[], 1), None);
176        assert_eq!(interpolation_search(&[5, 5, 5], 5), Some(0));
177        assert_eq!(interpolation_search(&[5, 5, 5], 4), None);
178    }
179
180    #[test]
181    fn exponential_hamma_elementni_topadi() {
182        let v: Vec<i32> = (0..1000).map(|x| x * 2).collect();
183        for (i, x) in v.iter().enumerate() {
184            assert_eq!(exponential_search(&v, x), Some(i), "x = {x}");
185        }
186        assert_eq!(exponential_search(&v, &1), None);
187        assert_eq!(exponential_search(&v, &10_000), None);
188        assert_eq!(exponential_search::<i32>(&[], &0), None);
189    }
190
191    #[test]
192    fn ternary_maksimumni_topadi() {
193        let x = ternary_search_max(0.0, 100.0, 1e-9, |x| -(x - 42.0).powi(2));
194        assert!((x - 42.0).abs() < 1e-4);
195    }
196}