Trie树的应用:查询IP地址的ISP
1. 问题描述
给定一个IP地址,如何查询其所属的ISP,如:中国移动(ChinaMobile),中国电信(ChinaTelecom),中国铁通(ChinaTietong)?现有ISP的IP地址区段可供下载,比如中国移动的IP地址段
103.20.112.0/22
103.21.176.0/22
111.0.0.0/20
112.0.0.0/10
117.128.0.0/10
120.192.0.0/10
183.192.0.0/10
211.103.0.0/17
211.136.0.0/14
211.140.0.0/15
211.142.0.0/17
211.142.128.0/17
211.143.0.0/16
218.200.0.0/14
218.204.0.0/15
218.206.0.0/15
221.130.0.0/15
221.176.0.0/13
223.112.0.0/14
223.116.0.0/15
223.120.0.0/13
223.64.0.0/11
223.96.0.0/12
36.128.0.0/10
39.128.0.0/10
上述网络地址是CIDR记法:IP地址/网络id位数,其中IP地址分为两部分
- 网络id
- 主机id
比如,192.168.23.35/21,其子网掩码为11111111 11111111 11111000 00000000即255.255.248.0,网络ID:192.168.00010111。IP地址103.20.112.168与地址段103.20.112.0/22前22位相匹配,则此IP地址属于中国移动。
2. Trie树实现查询
Trie树使用公共前缀,降低查询时间,减小了存储空间。为了构建Trie树,将IP地址二进制化(32位的二进制)。用于查询的Trie树一棵二叉树,满足以下性质:
- 非叶子节点的左孩子节点为0,右孩子节点为1;
- 叶子节点存储IP地址所对应的ISP。
Trie树的Java实现
/*
* Trie树,用于存储、检索ip地址
* 叶子节点标记为ip地址对应的ISP
*/
public class TrieTree {
private Node root = null; //根节点
/*二叉树的节点*/
private static class Node {
String element; //非叶子节点为空 叶子节点标记为ISP
Node[] children; //左孩子节点为0 右孩子节点为1
public Node() {
element = "";
children = new Node[2];
for (int i = 0; i < children.length; i++) {
children[i] = null;
}
}
}
public TrieTree() {
root = new Node();
}
/*插入ip地址*/
public void insert(Node root, String ipAddress, String isp) {
if(ipAddress.length() > 32) {
System.out.println("ip地址处理错误");
} else {
Node crawl = root;
for(int i=0; i<ipAddress.length(); i++) {
int index = (int) ipAddress.charAt(i) - '0';
if(crawl.children[index] == null) {
crawl.children[index] = new Node();
}
crawl = crawl.children[index];
}
crawl.element = isp;
}
}
public void insert(String ipAddress, String isp) {
insert(root, ipAddress, isp);
}
/*
* 检索ip地址,返回其所对应的ISP
* 若不在Trie树中,则返回null
* */
public String search(String binaryIP) {
Node crawl = root;
for(int i = 0; crawl.element.length() == 0; i++) {
int index = (int) binaryIP.charAt(i) - '0';
if(crawl.children[index] == null) {
return null;
}
crawl = crawl.children[index];
}
return crawl.element;
}
}
IP地址格式化
下面的IPFormat给出两个方法,实现
- 将IP地址转变成二进制
- 从CIDR记法的IP地址中得到网络ID部分
/*
* IP地址CIDR记法:network.host/size
* 比如:103.20.112.0/22
* 功能:将IP地址转换成其network地址
*/
public class IPFormat {
/*将ip地址转换成32位的二进制*/
public static String toBinaryNumber(String ipAddress) {
String[] octetArray = ipAddress.split("\\.");
String binaryNumber = "";
for(String str: octetArray) {
int octet = Integer.parseInt(str, 10);
String binaryOctet = Integer.toBinaryString(octet);
int bolength = binaryOctet.length();
if(bolength < 8) {
for (int i = 0; i < 8 - bolength; i++) {
binaryOctet = '0' + binaryOctet; //补前导0
}
}
binaryNumber += (binaryOctet);
}
return binaryNumber;
}
/*获取network地址部分*/
public static String getNetworkAddress(String cidrAddress) {
String[] cidrArray = cidrAddress.split("/");
String binaryNumber = toBinaryNumber(cidrArray[0]);
int size = Integer.parseInt(cidrArray[1]);
return binaryNumber.substring(0, size);
}
/*main方法用于测试*/
public static void main(String[] args) {
String ip = "103.20.112.0/20";
String bn = getNetworkAddress(ip);
System.out.println(bn);
}
}
Trie树的应用:查询IP地址的ISP的更多相关文章
- 【VB.NET】通过 IPIP.NET 数据库来查询IP地址
上一次介绍了利用纯真数据库查询IP地址详细信息的方法.然而纯真数据库是由网友反馈所提供的,很多数据描述并不准确,所以我上网找了一些其他的IP数据库,最后就找到了 ipip.net 这个网站所提供的IP ...
- 【VB.NET】利用纯真IP数据库查询IP地址及信息
几年前从某个博客抄来的,已经忘记原地址了,如果需要C#版的,可以在博客园搜到吧.我因为自己用,所以转换为了VBNET代码,而且也放置了很久,今天无意间翻出来,就分享给大家吧. 首先,先下载 纯真数据库 ...
- 查询ip地址归属地
查询ip地址归属地方法: curl ip.cn/$ip 如果没有返回,试试地址写全: curl https://www.ip.cn/$ip 如:
- Mac通过域名查询IP地址
Mac通过域名查询IP地址 方法一:使用Mac自带的"网络实用工具" 步骤: 搜索"网络使用工具",并打开: 点击LookUp,输入互联网地址,点击Lookup ...
- 在windows系统和linux系统中查询IP地址命令的不同
在linux和windows系统上查询IP地址的命令是不一样的. 在linux中的命令行模式下,输入ifconfig即可查询到IP.而在windows系统下要查询IP地址需要先打开do ...
- php查询ip地址来源归属地的脚本
<?php header('Content-Type:text/html;charset=utf-8'); if($_GET['sub']){ $ip = $_GET['ip']; $msg = ...
- 手机归属地查询-IP地址查询-身份证查询-域名备案查询--Api接口
使用这些接口是需要密钥的 公共密钥 appkey: 10003 secret: d1149a30182aa2088ef645309ea193bf 生成后sign: b59bc3ef6191eb9f ...
- Linux socket编程 DNS查询IP地址
本来是一次计算机网络的实验,但是还没有完全写好,DNS的响应请求报文的冗余信息太多了,不只有IP地址.所以这次的实验主要就是解析DNS报文.同时也需要正确的填充请求报文.如果代码有什么bug,欢迎指正 ...
- [Xcode 实际操作]八、网络与多线程-(11)使用同步Post方式查询IP地址信息
目录:[Swift]Xcode实际操作 本文将演示如何通过Post请求,同步获取IP地址信息. 一旦发送同步请求,程序将停止用户交互,直至服务器返回数据. 在项目导航区,打开视图控制器的代码文件[Vi ...
随机推荐
- 实现Ogre的脚本分离 - 天龙八部的源码分析(一)
目的 在研究天龙八部游戏的源码之时, 发现 Ogre 材质的模板部分被单独放在一个 material 文件之内, 继承模板的其他材质则位于另外的文件, 当我使用Ogre 官方源码, 加载脚本时其不会查 ...
- 基于uploadify.js实现多文件上传和上传进度条的显示
uploadify是JQuery的一个插件,主要实现文件的异步上传功能,可以自定义文件大小限制.文件类型.是否自动上传等属性,可以显示上传的进度条.官网地址是http://www.uploadify. ...
- 关于javascript模块加载技术的一些思考
前不久有个网友问我在前端使用requireJs和seajs的问题,我当时问他你们公司以前有没有自己编写的javascript库,或者javascript框架,他的回答是什么都没有,他只是听说像requ ...
- 【OpenGL(SharpGL)】支持任意相机可平移缩放的轨迹球实现
[OpenGL(SharpGL)]支持任意相机可平移缩放的轨迹球 (本文PDF版在这里.) 在3D程序中,轨迹球(ArcBall)可以让你只用鼠标来控制模型(旋转),便于观察.在这里(http://w ...
- easy-ui 小白进阶史(一):加载数据,easy-ui显示
作为一个没上过大学,没经过正规培训的96年的小白来说,找工作就没报特别大的希望,大不了找不到在回炉重造,继续学... 终于在海投了200份的简历之后...终于找到了...面试也挺简单的,,,第二天就去 ...
- http流请求时,被请求站点HttpContext.Current为null?
我负责运维一个短信接口站点sms.调用上游短信供应商下发短信后,他们会给我们推送发送报告.报告是类似DELIVRD.DI:9432这样的码.为了方便识别,系统里有一个报告码与其描述的关系,一开始是写死 ...
- wep.py输出hello world
webpy是python的一个简单的web开发的框架.可以通过简单的几行代码启动一个web服务(虽然只是输出helloworld). 准备工作 准备工具如下: 下载python[python开发环境] ...
- Eclipse 工程迁移到 Android Studio
目标:迁移成功,并成功正常运行! 附加:同步视频在文章后面! 两种方式: 1. 用Gradle导出,在Android Studio中用Gradle导入 (不推荐) 2. 用Android Studio ...
- Android开发学习之路-下拉刷新以及GridView的使用
GridView是类似于ListView的控件,只是GridView可以使用多个列来呈现内容,而ListView是以行为单位,所以用法上是差不多的. 主布局文件,因为要做下拉刷新,所以加了一个Prog ...
- Atitit 数据处理查询 中的异常标准化草案 jpa jdbc hb oql规范attilax总结
Atitit 数据处理查询 中的异常标准化草案 jpa jdbc hb oql规范attilax总结 Javaee6 与net 异常规范1 Jpa规范 JPA全称Java Persistence A ...