2017-01-30 40 views
0

我正在執行二進制搜索。該函數返回在數組中找到的目標值的索引,否則返回-1向下轉換數組長度和索引

我更喜歡處理i32索引,而不是usize,因爲當我找不到目標時我需要返回-1。我明確地在該函數的邊緣進行投射,我認爲這不是很好。什麼是更生鏽的方式呢?

fn binary_search(nums: &[i32], target: i32) -> i32 { 
    let num_size: i32 = nums.len() as i32;   // This seems bad 
    bsearch(nums, target, 0, num_size as usize) 
} 

fn bsearch(nums: &[i32], target: i32, lo: usize, hi: usize) -> i32 { 
    if hi < lo { 
     return -1; 
    } 

    let mid_idx = lo + ((hi - lo)/2); 
    let guess = nums[mid_idx]; 

    if guess > target { 
     bsearch(nums, target, lo, mid_idx - 1) 
    } else if guess < target { 
     bsearch(nums, target, mid_idx + 1, hi) 
    } else { 
     mid_idx as i32      // This seems bad 
    } 
} 
+1

您也可以查看[binary_search'的標準庫實現](https://doc.rust-lang.org/std/primitive.slice.html#method.binary_search)以獲得提示一種慣用的Rust方式會是什麼。 – Shepmaster

+0

沒有考慮到,謝謝! –

回答

7

你不必要地對抗語言。 i32不適用於數組索引。相反,你應該使用Option

fn binary_search(nums: &[i32], target: i32) -> Option<usize> { 
    let num_size = nums.len(); 
    bsearch(nums, target, 0, num_size) 
} 

fn bsearch(nums: &[i32], target: i32, lo: usize, hi: usize) -> Option<usize> { 
    if hi < lo { 
     return None; 
    } 

    let mid_idx = lo + ((hi - lo)/2); 
    let guess = nums[mid_idx]; 

    if guess > target { 
     bsearch(nums, target, lo, mid_idx - 1) 
    } else if guess < target { 
     bsearch(nums, target, mid_idx + 1, hi) 
    } else { 
     Some(mid_idx) 
    } 
} 

鑑於與使用usize爲指數陣列涉及的功能,有一個在迫使它使用i32,而不是沒有任何好處。如果您想要i32,因爲您要「找不到」爲-1,則可以在該功能完成後執行轉換。


注:另外,請記住,使用i32時,你真正應該做的邊界檢查。在64位系統上,陣列長度可能會大大超過i32可以表示的數量,甚至在32位機器上,您也會冒數組指數爲負的風險。

+0

我同意'Option'比哨兵值更清潔,但我認爲尺寸上的評論會更好。 「尤其是在64位系統上,陣列長度可能大大超過i32可以表示的*」理論上是這樣,但實際上多少時間處理超過20億個元素的陣列呢?除零尺寸類型外,對於最小可能的元素尺寸(u8),20億個元素至少爲2GB,並且尺寸從那裏向上。大多數軟件程序不需要處理任何大小的集合,因此強調它可能會削弱答案。 –

+0

@MatthieuM。我稍微改了一下,但是我不知道它已經是最後一段了。 –

+0

我拍了一下,如果你不喜歡,隨時還原。 –