1. 程式人生 > 實用技巧 >如何快速定位出一個IP地址的歸屬地?——二分查詢變體

如何快速定位出一個IP地址的歸屬地?——二分查詢變體

  • 查詢第一個值等於給定值的元素
  • 查詢最後一個值等於給定值的元素
  • 查詢第一個大於等於給定值的元素
  • 查詢最後一個小於等於給定值的元素
  • 查詢迴圈有序陣列中等於給定值的元素
#include <iostream>
#include <vector>
#include <stack>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include "TreeNode.h"
#include "ListNode.h"
using namespace std;

// 二分查詢具有O(logn)的時間複雜度,很強,但是隻能用於陣列的資料結構,像連結串列就不適合

// 二分查詢非遞迴法
int binarySearch(int num[], int length, int key){
    if(length < 1)
        return -1;
    int low = 0;
    int high = length - 1;
    int middle = 0;
    while(low <= high){
        // 以後儘量使用位運算,不直接用(low + high) / 2是為了防止加法溢位
        middle = low + ((high - low) >> 1);
        if(num[middle] == key)
            return middle;
        if(num[middle] > key)
            high = middle - 1;
        else if(num[middle] < key)
            low = middle + 1;
    }
    // 沒找到則返回-1
    return -1;
}

// 二分查詢遞迴方法
int binarySearchPlus(int num[], int low, int high, int key){
    if(low > high)
        return -1;
    int middle = low + ((high - low) >> 1);
    if(num[middle] == key)
        return middle;
    if(num[middle] > key)
        return binarySearchPlus(num, low, middle - 1, key);
    else
        return binarySearchPlus(num, middle + 1, high, key);
}

// 查詢第一個值等於給定值的元素
int binarySearchFirst(int num[], int length, int key){
    if(length < 1)
        return -1;
    int low = 0;
    int high = length - 1;
    int middle = 0;
    int min = 99999;
    while(low <= high){
        // 以後儘量使用位運算,不直接用(low + high) / 2是為了防止加法溢位
        middle = low + ((high - low) >> 1);
        if(num[middle] == key){
            // 只可能前面還有
            if(middle < min)
                min = middle;
            high = middle - 1;
        }
        else if(num[middle] > key)
            high = middle - 1;
        else if(num[middle] < key)
            low = middle + 1;
    }
    if(min != 99999)
        return min;
    // 沒找到則返回-1
    return -1;
}

// 查詢最後一個值等於給定值的元素(妙啊)
int binarySearchLast(int num[], int length, int key){
    if(length < 1)
        return -1;
    int low = 0;
    int high = length - 1;
    int middle = 0;
    int max = -2;
    while(low <= high){
        // 以後儘量使用位運算,不直接用(low + high) / 2是為了防止加法溢位
        middle = low + ((high - low) >> 1);
        if(num[middle] == key){
            // 只可能前面還有
            if(middle > max)
                max = middle;
            low = middle + 1;
        }
        else if(num[middle] > key)
            high = middle - 1;
        else if(num[middle] < key)
            low = middle + 1;
    }
    if(max != -2)
        return max;
    // 沒找到則返回-1
    return -1;
}

// 查詢第一個大於等於給定值的元素(和大於不一樣)
int binarySearchFirstHigh(int num[], int length, int key){
    if(length < 1)
        return -1;
    int low = 0;
    int high = length - 1;
    int middle = 0;
    while(low <= high){
        // 如果走到了最後,第一個大於給定值的元素肯定是下一個元素
        if(low == high){
            if(num[low] != key){
                if(low + 1 < length)
                    return low + 1;
                else
                    return -1;
            }
        }
        // 以後儘量使用位運算,不直接用(low + high) / 2是為了防止加法溢位
        middle = low + ((high - low) >> 1);
        if(num[middle] == key)
            return middle;
        if(num[middle] > key)
            high = middle - 1;
        else if(num[middle] < key)
            low = middle + 1;
    }
    // 沒找到則返回-1
    return -1;
}

// 查詢第一個大於等於給定值的元素(和大於不一樣)另一種解法,妙啊
int binarySearchFirstHighPlus(int num[], int length, int key){
    if(length < 1)
        return -1;
    int low = 0;
    int high = length - 1;
    int middle = 0;
    while(low <= high){
        middle = low + ((high - low) >> 1);
        if(num[middle] >= key){
            // 妙啊
            if(middle == 0 || num[middle - 1] < key)
                return middle;
            else
                // 往左走
                high = middle - 1;
        }
        else
            low = middle + 1;
    }
    return -1;
}

// 查詢第一個小於等於給定值的元素(和小於不一樣),妙啊
int binarySearchFirstLowPlus(int num[], int length, int key){
    if(length < 1)
        return -1;
    int low = 0;
    int high = length - 1;
    int middle = 0;
    while(low <= high){
        middle = low + ((high - low) >> 1);
        if(num[middle] <= key){
            if(middle == length - 1 || num[middle + 1] > key)
                return middle;
            else
                // 往右走
                low = middle + 1;
        }
        else
            high = middle - 1;
    }
    return -1;
}

// 在迴圈有序陣列中利用二分查詢元素
// 如果加大點兒難度,比如在迴圈有序陣列中查詢第一個等於某值的元素,比如在{3,4,5,6,1,2,3,4,5}中查詢4
int bsearchInCycleSortArray(int num[], int length, int key){
    if(length < 1)
        return -1;
    int low = 0;
    int high = length - 1;
    int middle = 0;
    while(low <= high){
        middle = low + ((high - low) >> 1);
        if(num[middle] == key)
            return middle;
        // 如果中間元素小於尾元素,說明右端是有序的,左端是迴圈的
        if(num[middle] < num[high]){
            // 如果目標元素在有序陣列範圍中,則後面的都是二分查詢
            if(num[middle] < key && key <= num[high])
                low = middle + 1;
            // 如果不在,則在另一半繼續查詢
            else
                high = middle - 1;
        }
        // 如果中間元素大於尾元素,說明左端是有序的,右端是迴圈的
        else{
            // 如果目標元素在有序陣列範圍中,則後面的都是二分查詢
            if(num[low] <= key && key < num[middle])
                high = middle - 1;
            // 如果不在,則在另一半繼續查詢
            else
                low = middle + 1;
        }
    }
    return -1;
}

int main(int argc, char* argv[]){

    int arr[6] = {4,5,6,1,2,3};

    cout<<bsearchInCycleSortArray(arr, 6, 2)<<endl;
    return 0;
}