系统url(路由验证),路由前缀树初代目
前段时间学习完算法与数据结构,经过了一段时间的经验总结,把以前写的第一套路由前缀树拿出了看看,
第一版有很多的不足,以及无法使用,仅供学术参考。不要在项目中使用!!
阅读该文章需要一定的算法基础,且我只是普通的开发程序员,并非算法岗职务,并不具有专业性
private final static Node NODE = new Node();
private static class Node {
int end;
HashMap<String, Node> map = new HashMap<>();
private Node() {
end = 0;
}
}
简单说一下思路,node在系统启动时,将白名单或黑名单,加载进入node对象中。end作为是否有此结束标识,里层map代表其他树枝。
图1
组成简易的抽象树形结构,如果bbb在名单中,则bbb上的end大于1,继续上代码
// 构建树方法,如果遇到没有的地方就创建分支,生成一颗完整的树
public static void insert(String url) {
if (url == null || url.length() < 2) {
return;
}
// 切分url 如 aa/bb/cc
// 变成['aa','bb','cc']
// aa/bb/cc.pdf为['aa','bb','cc.pdf']
String[] s = url.split("/");
// 拿出最后一项 cc.pdf
String e = s[s.length - 1];
Node n = NODE;
for (String u : s) {
// 截取第一个为空串,略过即可
if ("".equals(u)) {
continue;
}
// 判断下是否为最后一项
if (u.equals(e)) {
String[] h;
// 切点判断,在判断中,默认 ( . ) 一定为最后一项,将点前后分别生成树枝
// 主要是针对 **.pdf、**.png等等 请求路由不考虑其他乱序情况
// 如果不是,则继续向后执行
if ((h = u.split("\\.")).length > 1) {
if (h.length > 2) {
return;
}
// 根据插入值,生成树
if (n.map.get(h[0]) == null) {
n.map.put(h[0], new Node());
}
// 每一次等号复制的含义就像盖楼,每一次赋值就是前进一层
n = n.map.get(h[0]);
n.map.put(h[1], new Node());
n = n.map.get(h[1]);
n.end++;
// 上面四行代码 比如url: aa.pdf
// 结合更上面判空,如果aa不存在,构建aa树枝
// 踩到aa上面,生成pdf树枝
// 标记pdf树枝处有一个结束点
return;
}
}
// 这里不是最后一个 比如 : aa/bb/cc.pdf
// 这里是aa 或者bb
// 当前不存在,创建该树枝
if (n.map.get(u) == null) {
n.map.put(u, new Node());
}
// 爬到该树枝之上
n = n.map.get(u);
}
n.end++;
}
接下来就是使用该树验证url
public static boolean isMatch(String url) {
// 默认不存在过短的url 小众情况不考虑
if (url == null || url.length() < 2) {
return false;
}
// 该处与上面同理
String[] s = url.split("/");
String e = s[s.length - 1];
Node n = NODE;
for (String u : s) {
// 传统艺能 空串略过
if ("".equals(u)) {
continue;
}
if (n.map.get(u) == null) {
// 该处同理找到最后一个
if (u.equals(e)) {
String[] h;
if ((h = u.split("\\.")).length > 1) {
if (h.length == 2) {
//最后的判断单独判断
return judgeEnding(h, n);
}
}
}
// 遇到通配符 爬到通配符树枝上
if (n.map.get("*") != null) {
n = n.map.get("*");
continue;
}
// 遇到双*通配符 结束判断是否符合
if (n.map.get("**") != null) {
n = n.map.get("**");
break;
}
return false;
} else {
// 普通的爬树
n = n.map.get(u);
}
}
// 结束判断 是否有此结束项
return n.end > 0;
}
private static boolean judgeEnding(String[] h, Node n) {
if (n.map.get(h[0]) != null) {
// 如 结尾 为 aa.pdf 则爬aa树枝
n = n.map.get(h[0]);
} else if (n.map.get("*") != null) {
// 没有aa树枝 但是有通配符*树枝,则爬上*树枝
n = n.map.get("*");
} else {
// 没有树枝 则毁灭吧
n = null;
}
// 在此处 返回 不符合
if (n == null) {
return false;
}
// 该处为双重判断 为爬 pdf树枝 并且它必须存在
// 同时存在该处结尾
// 同时满足 则符合
return (n = n.map.get(h[1])) != null && n.end > 0;
}
end的主要作用,为 中间项url
如 树存在 aa/bb/cc 树枝 但不存在aa/bb
那么url aa/bb 再bb上end为0 不符合返回false
总结
该结构为本人自学数据结构与算法的学术性算法,该结构我明确表示是有问题的,不具备使用价值,在本人工作的项目中并没有引用该代码。
比如通配符url与普通url之间会互相影响,影响判断结果,但是主要是思路的展现与大家交流。
因为工作原因,没有时间一直去完善,但是目前已经完成了第二套更加稳定的路由前缀树算法结构,且目前没有发现问题,会在后续更新中与大家分享。