• 如何快速定位出一个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);
    }
    
    // 排序数组中第一次出现k的位置
    int binarySearchFirst(vector<int> num, int k, int length){
        int low = 0;
        int high = length - 1;
        int middle = 0;
        while(low <= high){
            middle = low + ((high - low) >> 1);
            if(num[middle] == k){
                if(middle > 0 && num[middle - 1] != k || middle == 0)
                    return middle;
                else
                    high = middle - 1;
            }
            else if(num[middle] > k)
                high = middle - 1;
            else
                low = middle + 1;
        }
        return -1;
    }
    
    // 最后一次出现k的位置
    int binarySearchLast(vector<int> num, int k, int length){
        int low = 0;
        int high = length - 1;
        int middle = 0;
        while(low <= high){
            middle = low + ((high - low) >> 1);
            if(num[middle] == k){
                if(middle < length - 1 && num[middle + 1] != k || middle == length - 1)
                    return middle;
                else
                    low = middle + 1;
            }
            else if(num[middle] > k)
                high = middle - 1;
            else
                low = middle + 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;
    }
    
  • 相关阅读:
    DES加密
    隐写术-隐藏明文的另类办法
    古典加密方法(三)转轮机
    古典加密方法(二)置换技术
    古典加密方法(一)代换技术
    基于加密算法的攻击类型的通俗解释(转载自知乎)
    指针小结
    幸福是什么?
    Jmeter常用脚本开发之FTP请求
    python自动发邮件总结及实例说明
  • 原文地址:https://www.cnblogs.com/flyingrun/p/13428168.html
Copyright © 2020-2023  润新知