簡體   English   中英

在Java中使用遞歸進行二進制搜索

[英]Binary Search using Recursion in java

我正在編寫一個用於遞歸二進制搜索的程序。 我有一個帶有一系列已排序數字的輸入文件,已將其添加到ArrayList中。 該程序搜索以查看用戶輸入給定的鍵是否在ArrayList中。

public static int binarySearch(int key, int median){
    if(key == (int)array.get(median)){
        return key;
    }else if(key < (int)array.get(median)){
        binarySearch(key,median-1);
    }else if(key > (int)array.get(median)){
        binarySearch(key,median+1);
    }
    return -1;
}

例如,假設密鑰為90。我調試​​了手表並將其放置在key和array.get(median)處。 在逐步執行該程序之后,我發現即使key和array.get(median)等於90,該程序也將繼續執行循環,而不會返回鍵。 我知道遞歸對此並不理想,但這是我需要使用的。

這看起來不像是正確的二進制搜索,因為二進制搜索使用分而治之的方法。 最初只對列表進行一次划分,然后檢查列表中的每個元素。 最好再重新划分列表,依此類推,請參見https://en.wikipedia.org/wiki/Binary_search_algorithm

無論如何,要使代碼運行,為什么沒有結果很可能是因為您沒有返回遞歸的結果,而是返回-1。

刪除return -1並在遞歸binarySearch調用之前設置return。 當您找不到該元素時,就會缺少退出條件。

示例(仍然不是正確的二進制搜索):

public static int binarySearch(int key, int median){
    if (median < 0 || median > array.size() - 1) { // element not found
        return -1;
    }
    if (key == (int)array.get(median)){
        return key;
    } else if(key < (int)array.get(median)){
        return binarySearch(key,median-1);
    } else{
        return binarySearch(key,median+1);
    }
}

您只關心它是否在數據結構中...

public static boolean binarySearch(int key, int median){

    if(key == (int)array.get(median)){
        return true;
    }else if(key < (int)array.get(median)){
        return binarySearch(key,median-1);
    }else if(key > (int)array.get(median)){
        return binarySearch(key,median+1);
    }
}

您的代碼可能會更好地編寫,但可以復制以理解其中的重要部分

您應該這樣更改代碼:

public static int binarySearch(int key, int median){
if(key == (int)array.get(median)){
    return key;
}else if(key < (int)array.get(median)){
    return binarySearch(key,median-1);
}else if(key > (int)array.get(median)){
    return binarySearch(key,median+1);
}
return -1;
}

如果這樣做,遞歸將結束,但我將留給您測試您的二進制搜索代碼。 在此方法中,您會忽略諸如開始索引和結束索引之類的東西。應該添加return語句,因為如果不這樣做,控件將移至方法中的下一條語句,這是不希望的。 希望有幫助!

發布的代碼不是 二進制搜索 ,實際上是使用遞歸的線性搜索。 二進制搜索將搜索空間划分為每一步的一半 ,二進制含義是上下文中的“兩半”。 結果是此線性搜索在O(n)中運行,而不是二進制搜索的預期O(lg n)邊界

問題/問題(比它不是一個二進制搜索等):

  • 遞歸案例中的值會丟失,因為它們本身不會返回。 遞歸案例的結果必須以某種方式使用(或者為什么要完全調用該函數?)。 在這種情況下,該值應直接返回,例如。 return binarySearch(..) 這會導致“在循環中繼續執行而不會返回鍵”-實際上它確實找到了鍵,但是卻丟棄了遞歸結果。

  • 該代碼無法正確檢測到越界終端條件。 找不到鍵時,這可能會導致IndexOutOfBoundsException。

  • 沒有進一步的邏輯,左/右步方法可能永遠無法正確終止。 例如,當列表為{1,3,5,7}且要查找的值為4時,原始代碼將在索引1(值3)和2(值4)之間進行乒乓操作。 這將導致引發StackOverflowError。

  • 密鑰被返回。 這一點意義不大,因為該密鑰已經為人所知,並且還防止了-1被檢測到。 而是返回找到的索引 ,如果只需要存在測試,則返回一個布爾值。

花一些時間來理解和解決這些問題..如果需要,請繼續閱讀以防破壞。


考慮重寫以解決上述問題。 請注意,它過於復雜 1,同時仍采用劣等算法和O(n)性能。 任何狀況之下;

// By taking in the List we make this function universal and not
// dependent upon a static field. It should probably take in a List<Integer>
// but I don't know what the actual type of "array" is. A more advanced
// implementation would take in List<Comparable> and then be modified to work
// with any objects that correctly implement said interface.
public static int linearSearch(int key, List list, int index, int step) {
    if (index < 0 || index >= list.size()) {
       // Base case: not found, out of bounds
       return -1;
    }

    int x = (int)list.get(index);
    if (key < x && step <= 0) {       // need to look left, NOT looking right
        // Recursive case: look left, returning result
        return linearSearch(key, list, index - 1, -1);
    } else if (key > x && step >= 0){ // need to look right, NOT looking left
        // Recursive case: look right, returning result
        return linearSearch(key, list, index + 1, +1);
    } else if (key == x) {
        // Base case: found key, return index found
        return index;  
    } else {
        // Base case: key not equal, refusing to ping-pong
        return -1;
    }
}

然后考慮使用此輔助函數/包裝函數;

// Returns the index in "array" where key was found, or -1 if it was not found
public static int linearSearch(int key) {
    // Have to start somewhere, might as well be the middle..
    // ..but it does NOT make the time complexity any better
    // ..and it is still NOT a Binary Search.
    return linearSearch(key, array, array.size() / 2, 0);
}

1或者,由於它線性搜索,因此可以重寫而無需額外的左右移動,並且具有相同的復雜度范圍。 (將這個簡單的代碼修改為遞歸二進制搜索也很簡單。)

public static int linearSearch(int key, List list, int index) {
    if (index >= list.size() {
        // Base case: end of list
        return -1;
    }

    int x = (int)list.get(index);
    if (key < x) {
        // Recursive case: not there yet, keep looking
        return linearSearch(key, list, index + 1);
    } else if (key == x) {
        // Base case: found key, return index
        return index;
    } else { // -> key > x
        // Base case: read past where the key would be found
        return -1;
    }
}

這是對ArrayList<Integer>的二進制搜索:)

public int binarySearch(List<Integer> list, int find) {
    int mid = list.size() / 2;
    int val = list.get(mid);

    if (val == find) {
        return val;
    } else if (list.size() == 1) {
        return -1;
    }

    return val > find ?
        binarySearch(list.subList(0, mid), find) :
        binarySearch(list.subList(mid, list.size()), find);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM