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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值