最近看到一则招聘的JD,附了一个算法题的链接,原题如下:

    请实现一个IP白名单过滤算法,实现以下接口
boolean addWhiteIpAddress(String ip);
boolean isWhiteIpAddress(String ip);
要求如下:
占用空间尽量少
运算效率尽量高
在内存中完成查询及判断
接口可能被并发询问
尽量能存储整个IP地址空间
代码可运行,且包含单测
  • 思路:

        如题,需要实现的是一个白名单的功能而不是黑名单,且要求尽可能存储整个IP地址空间,所以如果直接存储ip地址的字符串32位JVM下需要约:2^32 * (32+32+ (7+15)/2) = 300GB(这里只是非常粗略的估算),当然如果把字符串换成char数组可以省下对象头和类型指针,预计需约44GB,这完全超出了32位JVM的堆空间,而且就算借助于文件系统和硬盘,这么大数据量的字符串比较效率也是非常低下的。

        所以换个思路,针对IPV4,一个IP地址为32个bit位,可以直接将IP地址转换为int类型。又因为白名单只有两种状态,要么在白名单中,要么不在,所以很自然就想到位图了,用两个BitSet即可存储全部IPV4的地址,占用512M多的内存,也支持随机访问。

  • 缺点:

    1. volatile修饰,性能会降低(修饰对象或数组,如果对象属性或数组元素被修改,可以间接保证对象属性或数组元素的线程可见性)
    2. 目前没考虑IPV6
    3. 测试的数据量不够,可能有些边界还没考虑到,还没做性能测试
import java.util.BitSet;

import org.junit.Test;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils; public class IPFiliterTest {
// Java语言中没有无符号整形,int的最大值只能表示到0x7fffffff,所以需要两个BitSet来存储高低位
private static volatile BitSet low = new BitSet(Integer.MAX_VALUE);
private static volatile BitSet high = new BitSet(Integer.MAX_VALUE); /**
* 固定8位,前面不足的补零
* @param num
* @return
*/
private static String getByteBinaryStr(int num) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 8; i++) {
if ((num & 1) == 1) {
sb.append(1);
} else {
sb.append(0);
}
num = num >> 1;
}
return sb.reverse().toString();
} /**
* 将IP地址字符串转换为int
* @param ip
* @return
*/
private static int chgIpStrToInt(String ip) {
if (ip == null || StringUtils.isEmpty(ip)) {
throw new RuntimeException("Null string");
}
String[] arr = ip.split("\\.");
if (arr == null || arr.length != 4) {
throw new RuntimeException("Invalid ip");
}
if ("128.0.0.0".equals(ip)) {
return Integer.MIN_VALUE;
}
StringBuilder sb = new StringBuilder();
sb.append(getByteBinaryStr(new Integer(arr[0])));
sb.append(getByteBinaryStr(new Integer(arr[1])));
sb.append(getByteBinaryStr(new Integer(arr[2])));
sb.append(getByteBinaryStr(new Integer(arr[3])));
String intStr = sb.toString();
// Integer.valueOf处理负数会有问题
if (intStr.charAt(0) == '1') {
char[] chars = intStr.toCharArray();
chars[0] = '0';
intStr = new String(chars);
return 0 - Integer.valueOf(intStr, 2).intValue();
}
return Integer.valueOf(intStr, 2).intValue();
} public static boolean addWhiteIpAddress(String ip){
int ipInt = chgIpStrToInt(ip);
if (ipInt < 0) {
high.set(ipInt+Integer.MAX_VALUE+1);
} else {
low.set(ipInt);
}
return true;
} public static boolean isWhiteIpAddress(String ip) {
int ipInt = chgIpStrToInt(ip);
if (ipInt < 0) {
return high.get(ipInt+Integer.MAX_VALUE+1);
} else {
return low.get(ipInt);
}
} @Test
public void test() throws InterruptedException {
String ip1= "0.0.0.0";
addWhiteIpAddress(ip1);
Assert.isTrue(isWhiteIpAddress(ip1)); String ip2= "127.0.0.1";
addWhiteIpAddress(ip2);
Assert.isTrue(isWhiteIpAddress(ip2)); String ip3= "255.255.255.255";
addWhiteIpAddress(ip3);
Assert.isTrue(isWhiteIpAddress(ip3)); String ip4= "128.0.0.0";
addWhiteIpAddress(ip4);
Assert.isTrue(isWhiteIpAddress(ip4)); Assert.isTrue(!isWhiteIpAddress("0.0.0.1"));
Assert.isTrue(!isWhiteIpAddress("1.1.1.1"));
Assert.isTrue(!isWhiteIpAddress("001.001.001.001"));
}
}

最新文章

  1. 华为5700s配置链路聚合
  2. linux-redis
  3. 轻松自动化---selenium-webdriver(python) (五)
  4. 28 GroupSock(NetAddress)——live555源码阅读(四)网络
  5. Linux下执行程序出现 Text file busy 提示时的处理方式
  6. WebSphere应用服务器中https 请求协议的相关注意事项(服务器使用代理上Internet)
  7. mongoDb +Java+springboot
  8. 大规模集群FTP代理(基于lvs的vsftpd网络负载均衡方案部署(PASV))
  9. win8 远程桌面 你得凭证不工作
  10. MongoDB学习笔记&amp;lt;两&amp;gt;
  11. table 中的td 字段超长,超过部分用....表示
  12. 基于python创建一个简单的HTTP-WEB服务器
  13. 安利一下workflowy和Dynalist
  14. 利用BGP虚拟下一跳实现链路负载均衡
  15. [python]python3.7中文手册
  16. python--sort()和sorted()高级排序
  17. c#+.net常用功能点
  18. truncate和delete命令的优缺点和原理解析,适用场合
  19. 极光推送java代码
  20. Java将对象保存到文件中/从文件中读取对象

热门文章

  1. java泛型中使用的排序算法——归并排序及分析
  2. 干货,一文带你超详细了解 Filter 的原理及应用
  3. 用原生JS从零到一实现Redux架构
  4. 如何在招聘中考核.NET架构师
  5. 神奇的Scala Macro之旅(二)- 一个实例
  6. 简单Java类 全网最详细讲解 !!!
  7. Unity 用ml-agents机器学习造个游戏AI吧(1)(Windows环境配置)
  8. Java设置PPT幻灯片背景——纯色、渐变、图片背景
  9. 【swoole】使用swoole简单实现TCP服务
  10. iOS----------面试常问