您的位置:首页 > 其它

双重二分查找的应用

2016-11-06 20:39 218 查看
前几天面试的时候遇到一个问题,给定n个ip地址和m个ip地址块,如何判断,这n个地址是否在这m个ip地址块中的任意一个中。

后来想到了一个双重二分查找的方法,思路如下:

以IPv4地址为例,一共32位,为了方便记忆采用点分10进制方法标识。其本质是32位无符号整形,每一位不是0就是1,这样用来标

记2^32-1个不同的unsigned型整数,

每一个数代表一个网络地址。所以,对于一个给定的IP地址块,可以看成是一个具有上限和下限的unsigned整形区间,例如在区间

[142.235.6.34,142.235.160.140]之间

的IP地址其整形值的范围为[2397767202,2397806732],如果需要查询的IP地址转换成unsigned int型之后在上述区间,则表示命

中,否则没有命中。

在给定的n个地址块中,首先要进行重复区间的合并问题,这里涉及到区间树。区间树基于红黑树实现。这里先不作讨论。在测试例

子中我们生成n个没有交集的IP地址块。这样就

可以得到n个unsigned int型的区间,每一个区间的记为[low_i, high_i],low_i表示第i个地址块的下限,high_i表示第i个地址块的上

限,则有high_i-1<low_i(n>=i>=2)。

         下面以[10,20],[30,50], [70,90], [100,129], [150,210]这五个区间为例。

如果tar_num>210或是tar_num<10,则直接可以断定这个数不在给定的区间范围;

假设我们查找的数是tar_num=95,那么初始状态如下:





关键代码:

//二分查找法
bool binary_search_check(string ip){
int size = low.size();
unsigned int ip_int = str_to_uint(ip);
unsigned int t1 = high[size - 1], t2 = low[0];
if (ip_int >t1|| ip_int < t2)return false;
//判断上限范围
int low_t = 0,high_t=size-1,mid_t;
int low_index = -1;
while (low_t<high_t){
mid_t = (low_t + high_t)/2;
if (high[mid_t] < ip_int)low_t = mid_t + 1;
else high_t = mid_t;
}
low_index = low_t;//找到下限范围
//判断下限范围
low_t = 0, high_t = size - 1, mid_t;//当low和high相邻的时候,防止陷入死循环
int high_index = -1;
while (high_t-low_t>1){
mid_t = (low_t + high_t)/2;
if (low[mid_t] <= ip_int)low_t = mid_t;
else high_t = mid_t-1;
}
if (high_t==low_t) high_index = low_t;//找到下限范围
else{
if (low[high_t] > ip_int)high_index = low_t;
else high_index = high_t;
}
//判断
if (high_index == low_index)return true;
else return false;
}

以上是个人思路,若有不足,欢迎邮件讨论!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  双重二分查找