Skip to content

Commit b8fc4fe

Browse files
committed
ref: improve saddleback search
1 parent aad5192 commit b8fc4fe

File tree

1 file changed

+81
-54
lines changed

1 file changed

+81
-54
lines changed

src/searching/saddleback_search.rs

Lines changed: 81 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,112 @@
1-
// Saddleback search is a technique used to find an element in a sorted 2D matrix in O(m + n) time,
2-
// where m is the number of rows, and n is the number of columns. It works by starting from the
3-
// top-right corner of the matrix and moving left or down based on the comparison of the current
4-
// element with the target element.
51
use std::cmp::Ordering;
62

7-
pub fn saddleback_search(matrix: &[Vec<i32>], element: i32) -> (usize, usize) {
8-
// Initialize left and right indices
3+
/// Performs Saddleback search on a sorted 2D matrix.
4+
///
5+
/// The Saddleback search algorithm finds the position of a target element in a matrix where
6+
/// each row and each column is sorted in ascending order. The search starts from the top-right
7+
/// corner of the matrix and moves left or down based on comparisons with the target element.
8+
///
9+
/// # Arguments
10+
///
11+
/// * `matrix` - A 2D vector representing the sorted matrix.
12+
/// * `element` - The target element to search for.
13+
///
14+
/// # Returns
15+
///
16+
/// Returns a tuple (row, column) where both indices are 1-based. If the element is not found, returns (0, 0).
17+
pub fn saddleback_search(matrix: &[Vec<isize>], element: isize) -> (usize, usize) {
918
let mut left_index = 0;
1019
let mut right_index = matrix[0].len() - 1;
1120

12-
// Start searching
1321
while left_index < matrix.len() {
1422
match element.cmp(&matrix[left_index][right_index]) {
15-
// If the current element matches the target element, return its position (indices are 1-based)
1623
Ordering::Equal => return (left_index + 1, right_index + 1),
1724
Ordering::Greater => {
18-
// If the target element is greater, move to the next row (downwards)
1925
left_index += 1;
2026
}
2127
Ordering::Less => {
22-
// If the target element is smaller, move to the previous column (leftwards)
2328
if right_index == 0 {
24-
break; // If we reach the left-most column, exit the loop
29+
break;
2530
} else {
2631
right_index -= 1;
2732
}
2833
}
2934
}
3035
}
3136

32-
// If the element is not found, return (0, 0)
3337
(0, 0)
3438
}
3539

3640
#[cfg(test)]
3741
mod tests {
3842
use super::*;
3943

40-
// Test when the element is not present in the matrix
41-
#[test]
42-
fn test_element_not_found() {
43-
let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];
44-
assert_eq!(saddleback_search(&matrix, 123), (0, 0));
45-
}
46-
47-
// Test when the element is at the top-left corner of the matrix
48-
#[test]
49-
fn test_element_at_top_left() {
50-
let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];
51-
assert_eq!(saddleback_search(&matrix, 1), (1, 1));
52-
}
53-
54-
// Test when the element is at the bottom-right corner of the matrix
55-
#[test]
56-
fn test_element_at_bottom_right() {
57-
let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];
58-
assert_eq!(saddleback_search(&matrix, 300), (3, 3));
59-
}
60-
61-
// Test when the element is at the top-right corner of the matrix
62-
#[test]
63-
fn test_element_at_top_right() {
64-
let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];
65-
assert_eq!(saddleback_search(&matrix, 100), (1, 3));
66-
}
67-
68-
// Test when the element is at the bottom-left corner of the matrix
69-
#[test]
70-
fn test_element_at_bottom_left() {
71-
let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];
72-
assert_eq!(saddleback_search(&matrix, 3), (3, 1));
44+
macro_rules! saddleback_tests {
45+
($($name:ident: $tc:expr,)*) => {
46+
$(
47+
#[test]
48+
fn $name() {
49+
let (matrix, element, expected) = $tc;
50+
assert_eq!(saddleback_search(&matrix, element), expected);
51+
}
52+
)*
53+
};
7354
}
7455

75-
// Additional test case: Element in the middle of the matrix
76-
#[test]
77-
fn test_element_in_middle() {
78-
let matrix = vec![
79-
vec![1, 10, 100, 1000],
80-
vec![2, 20, 200, 2000],
81-
vec![3, 30, 300, 3000],
82-
];
83-
assert_eq!(saddleback_search(&matrix, 200), (2, 3));
56+
saddleback_tests! {
57+
test_element_not_found: (
58+
vec![
59+
vec![1, 10, 100],
60+
vec![2, 20, 200],
61+
vec![3, 30, 300]
62+
],
63+
123,
64+
(0, 0),
65+
),
66+
test_element_at_top_left: (
67+
vec![
68+
vec![1, 10, 100],
69+
vec![2, 20, 200],
70+
vec![3, 30, 300]
71+
],
72+
1,
73+
(1, 1),
74+
),
75+
test_element_at_bottom_right: (
76+
vec![
77+
vec![1, 10, 100],
78+
vec![2, 20, 200],
79+
vec![3, 30, 300]
80+
],
81+
300,
82+
(3, 3),
83+
),
84+
test_element_at_top_right: (
85+
vec![
86+
vec![1, 10, 100],
87+
vec![2, 20, 200],
88+
vec![3, 30, 300]
89+
],
90+
100,
91+
(1, 3),
92+
),
93+
test_element_at_bottom_left: (
94+
vec![
95+
vec![1, 10, 100],
96+
vec![2, 20, 200],
97+
vec![3, 30, 300]
98+
],
99+
3,
100+
(3, 1),
101+
),
102+
test_element_in_middle: (
103+
vec![
104+
vec![1, 10, 100, 1000],
105+
vec![2, 20, 200, 2000],
106+
vec![3, 30, 300, 3000],
107+
],
108+
200,
109+
(2, 3),
110+
),
84111
}
85112
}

0 commit comments

Comments
 (0)