简述一下项目中手写的Token验证服务设计过程
PART A 设计校验的哈希算法
这里直接展示整个项目中用到的算法库,其中涉及位运算的可不管
直接应用到的方法是hash(str)
大概流程如下
1.构造一个大素数表并随机打乱
2.提供足够快的快速幂
3.哈希规则:\sum 下标对应byte^^randomPrimes[下标 % 素数表长度] % 128
为了更快的hash过程其实可以把下标进一步转为其bitcount,这样算幂会把log的复杂度略降一点
package com.noresp.oj.utils;
/**
* 方便OJ搭建的简易算法库
* 目前可提供:
* 随机大素数表
* 随机打乱
* 哈希(注意:特定用途)
* 整型交换、bitcount、fastPow
* 随机数
*/
public class AlgsUtils {
private static final int[] bitmasks = new int[0x100];
private static final int[] randomPrimes = new int[1<<10];
public static final long magicNumber = 19260817L;
public static class SimpleRandom {
long seed = 1L;
public void setSeed(long seed) {
this.seed = seed;
}
/**
* 简易高效的手写随机数
* 大概比Math.random快20倍(2^^26数量级下)
* @return 随机数
*/
public long next() {
seed = seed*1103515245+12345 & 0xffffffffL; // 模拟unsigned int // 切记0xffffffff没有L会翻车。。
return seed >> 16;
}
public int next(int mod) {
return (int)(next()%mod);
}
}
static {
initializeBitmasks();
initializePrimeTable();
randomShuffle(randomPrimes,magicNumber);
}
/**
* O(n)打长度为n的二进制表
* 测试通过
*/
private static void initializeBitmasks() {
for(int i = 0xff; i > 0; --i) {
if(bitmasks[i] != 0) continue;
for(int j = i; j > 0; j -= j&-j) {
bitmasks[i]++;
}
for(int j = i, k = 0; j > 0; j -= j&-j, k++) {
bitmasks[j] = bitmasks[i]-k;
}
}
}
/**
* 计算二进制1的个数
* 测试通过
* @param value
* @return
*/
public static int bitCount(int value) {
int result = 0;
for(; value > 0; value >>>= 8) {
result += bitmasks[value & 0xff];
}
return result;
}
/**
* 通过固定的随机素数进行哈希/加密
* 哈希串 = \sum 下标对应byte^^randomPrimes[下标 % 素数表长度] % 128
* 时间复杂度O(n log2(log2m)),其中n为字符串长度,m为最大的随机素数大小
* @param string
* @return
*/
public static String hash(String string) {
if(string == null || string.length() == 0) return null;
byte[] b = string.getBytes();
for(int i = 0; i < b.length; i++) {
int j = b[i];
int k = randomPrimes[i & randomPrim