条件:

给出一个文件,其中每行一个IP段(IPv4,其实IPv6类似,只是规模剧增)及其对应的信息(例如物理地址信息),内容及格式为:

<start_IP> <end_IP> <country> <province/state> <city> <other_info>

内容说明:

1. <start_IP> <end_IP>都为包含状态,即[<start_IP>, <end_IP>]

2. 各IP段不重合

3. IP段有空洞,即有些IP不能找到对应段

问题:

给出一个IP,请实现算法返回其对应的<country> <province/state> <city> <other_info>等信息

算法一:

扩展每个IP段,构造每个IP与其对应<country> <province/state> <city> <other_info>信息的结构,以IP作key读入内存

优点:简单易实现

缺点:占用内容过大

算法二:

扩展每个IP段,构造每个IP与其对应<country> <province/state> <city> <other_info>信息的数据,以IP作key写入数据库

优点:简单易实现

缺点:需要额外的数据库服务,使用频繁时性能不高

算法三:

近似查找。此方法有两个关键点:

1. 查找过程中需要比较IP的大小,因此需要实现IP的比较。也有两种实现:1) 实现一个IP的比较器 2) 把IP转换为数字:IP看作是一个4位的数字,每位之间进制256,例如10.13.183.72=10 * 256^3 + 13 * 256^2 + 183 * 256^1 + 72 * 256 ^0,这样需把给定的IP和每一段IP的<start_IP>, <end_IP>都做相同转换,便于比较

代码:

long num = 16777216L * Long.parseLong(ips[0]) + 65536L
* Long.parseLong(ips[1]) + 256 * Long.parseLong(ips[2])
+ Long.parseLong(ips[3]); return num;

或更快速的移位实现:

long num = 0;
for (int i = 0; i < ips.length; i++) {
num += Long.parseLong(ips[i]) << (8 * (ips.length - 1 - i));
}
return num;

2. 查找算法需要改进,因为是查找一个值所属的范围,并非直接命中式的查找。以折半查找为例,改造如下:

1) 将IP段的<start_IP>转换为数字,构造查询有序数组A。以每段的<end_IP>构造另一个备查数组B,同一段的<start_IP> <end_IP>在各自数组中索引一致。

2) 命中算法改为近似算法,更精确的叫作向下最近算法,基于数组A执行折半查找

3) 以A中的索引位查找数组B,确认目标IP在对应段中。防止误查本应在空洞段中的IP

    #数组A
private List<Long> startIPNOsList = new ArrayList<Long>();
#数组B
private List<Long> endIPNOsList = new ArrayList<Long>();
#对应信息数组C
private List<Address> addressList = new ArrayList<Address>(); //...构造上述数组 /**
* 实现查找
*/
public Address detect(String ip) {
long ipNO = IPv4Util.convertIP2Long(ip); if (ipNO > 0) {
int idx = containBinSearch(ipNO, 0, startIPNOsList.size() - 1);
if (idx > 0 && ipNO <= endIPNOsList.get(idx)) {
return addressList.get(idx);
}
}
short zero = 0;
return new Address(zero, zero, zero);
} /**
* 如果arr[i] <= target && arr[i + 1] > target,则返回i
* @param target 查找目标
* @param low
* @param high
* @return
*/
private int containBinSearch(long target, int low, int high) {
//表示没查到
if (high < low) {
return -1;
} int mid = (low + high) / 2;
if (mid == startIPNOsList.size() - 1) {
return mid;
} if (startIPNOsList.get(mid) > target) {
return containBinSearch(target, low, mid - 1);
} else if (startIPNOsList.get(mid + 1) <= target) {
return containBinSearch(target, mid + 1, high);
} else {
return mid;
}
}

优点:占用内存小,查询速度不错

缺点:实现稍复杂

算法四:

Trie树实现。

“Trie树即字典树。

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

它有3个基本性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符; 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串; 每个节点的所有子节点包含的字符都不相同。” -- 详见 字典树

具体实现:扩展每个IP段,将每个IP加入Trie树。每个ip位构造一个节点,每个叶子节点包含<country> <province/state> <city> <other_info>等信息,最后构造一个5层的trie树。
优点:查询速度快,实现较简单
缺点:占用内存超大

算法五:
近似trie树查找。基本结构与算法四相同,查找算法需改进,构造树时需在叶节点中包含<end_ip>。
实现:
对于IP第1-4位,分别在trie树第2-5层节点应用如下逻辑
  1 查找当前层中最大的不大于当前位的节点
     a) 如果当前节点是叶节点,验证目标IP是否大于<end_ip>:大于返回空,否则返回对应<country>等信息
     b) 如果查找到的节点值等于当前位的值,向下一层重复此逻辑
     c) 如果查找到的节点值小于当前位的值,返回本节点最大值的叶节点
  2 如果查找不到,本节点的父节点值 -1,本节点及其各子节点置为255,返回上一层重复此逻辑

优点:速度快,较算法4占内存小
确定:查找算法复杂,内存占用仍旧很大

五种算法实现IP到地址的转换的更多相关文章

  1. 可以进行SHA-1,SHA-224,SHA-256,SHA-384,SHA-512五种算法签名的工具类,以及简单说明

    import java.security.MessageDigest; public class SignatureSHA { public static String signSHA(String ...

  2. [转]nginx负载均衡的五种算法

    1.round robin(默认) 轮询方式,依次将请求分配到各个后台服务器中,默认的负载均衡方式. 适用于后台机器性能一致的情况. 挂掉的机器可以自动从服务列表中剔除. 2.weight 根据权重来 ...

  3. 五种基于RGB色彩空间统计的皮肤检测算法

    最近一直在研究多脸谱识别以及如何分辨多个皮肤区域是否是人脸的问题 网上找了很多资料,看了很多篇文章,将其中基于RGB色彩空间识别皮肤 的统计算法做了一下总结,统计识别方法主要是简单相比与很多其它基于 ...

  4. LeetCode算法题-Number Complement(Java实现-五种解法)

    这是悦乐书的第240次更新,第253篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第107题(顺位题号是476).给定正整数,输出其补码数.补充策略是翻转其二进制表示的位 ...

  5. LeetCode算法题-Longest Palindrome(五种解法)

    这是悦乐书的第220次更新,第232篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第87题(顺位题号是409).给定一个由小写或大写字母组成的字符串,找到可以用这些字母构 ...

  6. LeetCode算法题-Find the Difference(Java实现-五种解法)

    这是悦乐书的第214次更新,第227篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第82题(顺位题号是389).给定两个字符串s和t,它们只包含小写字母.字符串t由随机混 ...

  7. 数组复制的五种方式(遍历循环一一赋值、System.arraycopy、地址赋值、克隆clone()、Arrays.copyof())

    package com.Summer_0424.cn; import java.util.Arrays; import java.util.concurrent.CopyOnWriteArrayLis ...

  8. Windows五种IO模型性能分析和Linux五种IO模型性能分析

    Windows五种IO模型性能分析和Linux五种IO模型性能分析 http://blog.csdn.net/jay900323/article/details/18141217 http://blo ...

  9. 五种WordPress防止垃圾评论方法-过滤垃圾评论提高WP运行效率

    WordPress貌似和垃圾评论是一对“孪生兄弟”,无论在国内还是国外的空间主机上搭建的Wordpress博客,无论Wordpress有多少流量多么低的权重,垃圾评论都会自动找上门来,假如有好几天没有 ...

随机推荐

  1. Mac iphone 使用 如何修改apple 用户名 XXX的mac Mac 与iphone如何连接 传递文件 为iphone增加铃声 iphone铃声的制作---城

    1.更改mac apple id Apple ID 即用户名称,您可以将其用于与 Apple 有关的所有操作.为某个 Apple 服务(如 iCloud 或 App Store)创建帐户时即创建了 A ...

  2. FineReport——权限分配以及自定义首页

    权限分配可以有两种方法,第一种方法是根据部门职位分配权限,第二种是根据角色分配权限: FR自带有三个JQ对象,用以保存用户名参数/角色参数/部门参数——$fr_username/$fr_authori ...

  3. C#面向对象(OOP)入门—第二天—多态和继承(继承)

    介绍: 第一天的内容主要是不同情形下的方法重载.这一部分则主要讲面向对象中继承的概念.首先用一个要点图形来定义继承. 继承 一个简单的例子: ClassA: class ClassA:ClassB { ...

  4. php设计模式五----适配器模式

    1.简介 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁.这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能. 意图:将一个类的接口转换成客户希望的另外一个接口 ...

  5. mongo数据库基本操作--python篇

    连接数据库 MongoClient VS Connection class MongoClient(pymongo.common.BaseObject) | Connection to MongoDB ...

  6. 【C++】C++11的auto和decltype关键字

    转自: http://www.linuxidc.com/Linux/2015-02/113568.htm 今天要介绍C++11中两个重要的关键字,即auto和decltype.实际上在C++98中,已 ...

  7. QT中ui更改后不能更新的解决方法

    ui源文件到界面显示的原理可以网上搜索,这里不再描述.简单讲就是先要从*.ui生成ui_*.h然后再编译,所以界面未更新实际上是因为ui_*.h这个文件没有更新导致的. 出现此问题后我尝试了以下几个方 ...

  8. maven中profile的激活方式

    1.默认激活 Maven给我们提供了多种不同的profile激活方式.比如我们可以使用-P参数显示的激活一个profile,也可以根据环境条件的设置让它自动激活等. <profile> & ...

  9. Monty Hall悖论

    Monty Hall悖论又称为蒙提·霍尔悖论.三门问题.Monty Hall是上个世纪60年代,电视游戏节目“Let's Make a Deal”的主持人,这个悖论便是以他的名字来命名的.节目的规则是 ...

  10. centos6.9 部署wordpress

    用centos6.9搭建wordpressLinux.Nginx.Mariadb(Mysql).PHP 1 yum install nginx mariadb php php-fpm php-mysq ...