1use std::cmp::Ordering;
6
7pub fn bisect<T: Ord>(data: &[T], x: &T) -> usize {
22 bisect_right(data, x)
23}
24
25pub fn bisect_left<T: Ord>(data: &[T], x: &T) -> usize {
39 let mut lo = 0;
40 let mut hi = data.len();
41 while lo < hi {
42 let mid = lo + (hi - lo) / 2;
43 if data[mid] < *x {
44 lo = mid + 1;
45 } else {
46 hi = mid;
47 }
48 }
49 lo
50}
51
52pub fn bisect_right<T: Ord>(data: &[T], x: &T) -> usize {
66 let mut lo = 0;
67 let mut hi = data.len();
68 while lo < hi {
69 let mid = lo + (hi - lo) / 2;
70 if data[mid] <= *x {
71 lo = mid + 1;
72 } else {
73 hi = mid;
74 }
75 }
76 lo
77}
78
79pub struct Bisector<T, K> {
101 accessor: Box<dyn Fn(&T) -> K>,
102}
103
104impl<T, K: PartialOrd> Bisector<T, K> {
105 pub fn new<F>(accessor: F) -> Self
107 where
108 F: Fn(&T) -> K + 'static,
109 {
110 Self {
111 accessor: Box::new(accessor),
112 }
113 }
114
115 pub fn left(&self, data: &[T], x: K) -> usize {
117 let mut lo = 0;
118 let mut hi = data.len();
119 while lo < hi {
120 let mid = lo + (hi - lo) / 2;
121 if (self.accessor)(&data[mid]) < x {
122 lo = mid + 1;
123 } else {
124 hi = mid;
125 }
126 }
127 lo
128 }
129
130 pub fn right(&self, data: &[T], x: K) -> usize {
132 let mut lo = 0;
133 let mut hi = data.len();
134 while lo < hi {
135 let mid = lo + (hi - lo) / 2;
136 if (self.accessor)(&data[mid]) <= x {
137 lo = mid + 1;
138 } else {
139 hi = mid;
140 }
141 }
142 lo
143 }
144
145 pub fn center<'a>(&self, data: &'a [T], x: K) -> Option<&'a T>
147 where
148 K: Copy + std::ops::Sub<Output = K>,
149 {
150 if data.is_empty() {
151 return None;
152 }
153 let i = self.left(data, x);
154 if i == 0 {
155 return Some(&data[0]);
156 }
157 if i >= data.len() {
158 return Some(&data[data.len() - 1]);
159 }
160 Some(&data[i])
162 }
163}
164
165pub fn least_index(data: &[f64], x: f64) -> Option<usize> {
176 if data.is_empty() {
177 return None;
178 }
179 let i = bisect_left_f64(data, x);
180 if i == 0 {
181 return Some(0);
182 }
183 if i >= data.len() {
184 return Some(data.len() - 1);
185 }
186 let dist_left = (data[i - 1] - x).abs();
188 let dist_right = (data[i] - x).abs();
189 if dist_left <= dist_right {
190 Some(i - 1)
191 } else {
192 Some(i)
193 }
194}
195
196pub fn bisect_left_f64(data: &[f64], x: f64) -> usize {
198 let mut lo = 0;
199 let mut hi = data.len();
200 while lo < hi {
201 let mid = lo + (hi - lo) / 2;
202 match data[mid].partial_cmp(&x) {
203 Some(Ordering::Less) => lo = mid + 1,
204 _ => hi = mid,
205 }
206 }
207 lo
208}
209
210pub fn bisect_right_f64(data: &[f64], x: f64) -> usize {
212 let mut lo = 0;
213 let mut hi = data.len();
214 while lo < hi {
215 let mid = lo + (hi - lo) / 2;
216 match data[mid].partial_cmp(&x) {
217 Some(Ordering::Greater) => hi = mid,
218 _ => lo = mid + 1,
219 }
220 }
221 lo
222}
223
224pub fn binary_search<T: Ord>(data: &[T], x: &T) -> Option<usize> {
237 data.binary_search(x).ok()
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[test]
245 fn test_bisect_left() {
246 let data = vec![1, 2, 3, 3, 3, 5, 8];
247 assert_eq!(bisect_left(&data, &0), 0);
248 assert_eq!(bisect_left(&data, &1), 0);
249 assert_eq!(bisect_left(&data, &3), 2);
250 assert_eq!(bisect_left(&data, &4), 5);
251 assert_eq!(bisect_left(&data, &9), 7);
252 }
253
254 #[test]
255 fn test_bisect_right() {
256 let data = vec![1, 2, 3, 3, 3, 5, 8];
257 assert_eq!(bisect_right(&data, &0), 0);
258 assert_eq!(bisect_right(&data, &1), 1);
259 assert_eq!(bisect_right(&data, &3), 5);
260 assert_eq!(bisect_right(&data, &4), 5);
261 assert_eq!(bisect_right(&data, &9), 7);
262 }
263
264 #[test]
265 fn test_bisector() {
266 #[derive(Debug)]
267 struct Item {
268 value: i32,
269 }
270
271 let bisector = Bisector::new(|item: &Item| item.value);
272 let data = vec![
273 Item { value: 1 },
274 Item { value: 3 },
275 Item { value: 3 },
276 Item { value: 5 },
277 ];
278
279 assert_eq!(bisector.left(&data, 3), 1);
280 assert_eq!(bisector.right(&data, 3), 3);
281 }
282
283 #[test]
284 fn test_least_index() {
285 let data = vec![1.0, 2.0, 5.0, 8.0, 13.0];
286 assert_eq!(least_index(&data, 0.0), Some(0));
287 assert_eq!(least_index(&data, 3.0), Some(1)); assert_eq!(least_index(&data, 6.0), Some(2)); assert_eq!(least_index(&data, 20.0), Some(4));
290 }
291
292 #[test]
293 fn test_binary_search() {
294 let data = vec![1, 2, 3, 5, 8, 13];
295 assert_eq!(binary_search(&data, &5), Some(3));
296 assert_eq!(binary_search(&data, &4), None);
297 }
298}