一.主要思想(进位制思想与移位思想):
{
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
, "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
}
1).进位制思想
将0-9-a-Z,62个字符做为一个数制表系统,存入一个数组,既62位数字进制,逢"Z"数制进一位,好比9进一位到10。
4位串码前位不够补0,累加的操作只需要将末位往后移动一位循环移动。
由进位制思想可以推出,假如数制表长度为n,在n个无重复元素集合中,取m个元素做组合(长度为x,组合时可复用单个元素),组成为不同的串码组合,可以有n的m次方(n^m或n^x)种组合,即:
C(n,m)=n^m或=n^x;
若 m=4,则C(n,m)=62^4=14776336;//≈1477万
若 m=5,则C(n,m)=62^5=916132832;//≈9亿
若 m=6,则C(n,m)=62^5=56800235584;//≈568亿
以此类推。
2).移位思想
比如:
已知串码[a][b][c][d]
求下一位串码
将末位[d]往后移一位得到:[e]
故求得下一位串码是[a][b][c][e]
二.实现思路
方式1
输入参数:当前串码
输出:新的串码方式2
根据10进制数值,换算出指定长度的62进制的数串
三.下面走 java代码实现( CombinationCodeV4衍生版本 )
/**
* Copyright (C), 2000-2021, XXX有限公司
* FileName: CombinationCodeV4衍生版本
* Author: wangyetao
* Date: 21-10-23 21:00:00
* Description:使用10个数字与52个字母生成n个不重复的n位串码,相当于62位数进制
* 将0-9-A-z,62个字符做为一个进制系统,存入一个数组,既62位数字进制,4位串码前位不够补0。
* 累加的操作只需要将末位往后移动一位循环移动,逢"Z"数制进一位。好比9进一位到10。
* <p>
* 比如:
* * 已知串码[a][b][c][d]
* * 求下一位串码
* * 将末位[d]往后移一位得到:[e]
* * 故求得下一位串码是[a][b][c][e]
* 主要思路:
* * 补位+进位+递归
* <p>
* History:
* <author> <time> <version> <desc>
* 作者姓名 修改时间 版本号 版本描述
* wangyetao,21-10-21 15:29:22,CombinationNumberV2,版本描述
* wangyetao,21-10-23 08:30:24,CombinationNumberV3,进位逻辑改用[递归]实现
* wangyetao,21-10-23 21:00:00,CombinationCodeV4衍生版本,添加next方法
*/
package simple.callback.cryptographyalgorithm;
/**
* @ClassName: CombinationNumberV3
* @Description: java类描述
* @Author: wangyetao
* @Date: 21-10-23 08:30:24
*/
public class CombinationCodeV4 {
//数制表
private static String[] digitalsystemtable = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
, "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
};
private static int DIGITALMETER_LENGTH = digitalsystemtable.length;//数制表长度
private int defaultDigit = 4;//数位默认长度
public static int countIndex = 0;//10进制数字记数器
/**
* 根据当前串码获取下一位串码
*
* @param digit 数位长度
* @param currentCodeStr 当前串码
* @return 获取下一位串码
*/
public String generateNextCode(int digit, String currentCodeStr) {
defaultDigit = digit;
String[] digitalTempArr = currentCodeStr.split("");
String[] digitalArr = new String[defaultDigit];
//串码检测
boolean isCompliance = filterCharacter(currentCodeStr);
if (!isCompliance) {
return "不合规的串码参数";
}
//补位检测
digitalArr = doComplement(digitalTempArr);
//保存单独位值
String[] singleDigital = new String[defaultDigit];
for (int i = 0; i < digitalArr.length; i++)
singleDigital[i] = digitalArr[i];
//进位开关
boolean[] singleCarryup = new boolean[defaultDigit];
int carryupLength = singleCarryup.length;
for (int i = 0; i < carryupLength; i++)
singleCarryup[i] = false;
//进位思想主要逻辑递归代码
singleDigital = recursiveNext(singleDigital, singleCarryup, 1);
countIndex++;
//拼接单独位值
StringBuffer tmpBuff = new StringBuffer();
for (String tmp : singleDigital)
tmpBuff.append(tmp);
return tmpBuff.toString();
}
/**
* 数制运算与递归进位运算
*
* @param inSingleDigital 单独位值
* @param inSingleCarryup 进位开关
* @param step 步长为1
*/
private String[] recursiveNext(String[] inSingleDigital, boolean[] inSingleCarryup, int step) {
String[] singleDigital = inSingleDigital;
boolean[] singleCarryup = inSingleCarryup;
//步长控制A处:步长不能超过进位开关数长度;递归出口条件;
//当步长大于进位开关数长度时,说明此时所有的位值均须进位,此时首位已到达最大值,无须再进位,归为0,进入下一轮。
if (step <= singleDigital.length) {
int inBinary62Index = indexOfDigitalsystemtable(singleDigital[defaultDigit - step]);
inBinary62Index++;//下标后移一位
if (inBinary62Index > DIGITALMETER_LENGTH - 1) {//进位检测
singleDigital[defaultDigit - step] = digitalsystemtable[0];//数制进位前,本位归0
singleCarryup[singleCarryup.length - step] = true;//打开开关,数制进一位
if (singleCarryup[singleCarryup.length - step]) {
step++;
recursiveNext(singleDigital, singleCarryup, step);//进位递归
}
} else {
singleDigital[defaultDigit - step] = digitalsystemtable[inBinary62Index];//单独位值取后移一位的值,即"+1"
}
}
return singleDigital;
}
/**
* 补位,前位不够补0
*
* @param inDigitalTempArr
* @return targetArr
*/
private String[] doComplement(String[] inDigitalTempArr) {
String[] inTempArr = inDigitalTempArr;//[1][2][3]
String[] targetArr = new String[defaultDigit];//[][][][]
int differ = targetArr.length - inTempArr.length;
//补位,前位不够补0
if (inTempArr.length < targetArr.length) {
//1)保存已有的值到目标数组
for (int i = 0; i < inTempArr.length; i++)
targetArr[i + differ] = inTempArr[i];
//2)补位
for (int i = 0; i < differ; i++)
targetArr[i] = "0";
} else {
for (int i = 0; i < defaultDigit; i++)
targetArr[i] = inTempArr[i];
}
return targetArr;
}
/**
* 根据当前串码获取下一位串码
*
* @param digit 数位长度
* @param currentCodeStr 当前串码
* @return 获取下一位串码
*/
private String next(int digit, String currentCodeStr) {
return generateNextCode(digit, currentCodeStr);
}
/**
* 此方法无须传入当前串码,方法内根据countIndex生成下一位串码
* 仅适用在全局单例环境下,由10进制数字转换出62进制的数字串码
*
* @param digit 数位长度
* @return 串码
*/
public String next(int digit) {
defaultDigit = digit;
//将10进制数字转换出62进制的数字串码
String _10_62code = BinaryConversion._10_to_62(countIndex, defaultDigit);
String[] digitalTempArr = _10_62code.split("");
String[] digitalArr = new String[defaultDigit];
//补位检测
digitalArr = doComplement(digitalTempArr);
//保存单独位值
String[] singleDigital = new String[defaultDigit];
for (int i = 0; i < digitalArr.length; i++)
singleDigital[i] = digitalArr[i];
//进位开关
boolean[] singleCarryup = new boolean[defaultDigit];
int carryupLength = singleCarryup.length;
for (int i = 0; i < carryupLength; i++)
singleCarryup[i] = false;
//进位思想主要逻辑递归代码
singleDigital = recursiveNext(singleDigital, singleCarryup, 1);
countIndex++;
//拼接单独位值
StringBuffer tmpBuff = new StringBuffer();
for (String tmp : singleDigital)
tmpBuff.append(tmp);
return tmpBuff.toString();
}
/**
* 根据10进制的数值生成指定长度的62进制的对应码
*
* @param digit 数位长度
* @param _10num 10进制数值
* @return
*/
public String next(int digit, int _10num) {
defaultDigit = digit;
//将10进制的数值转换出62进制的数字串码
String _10_62code = BinaryConversion._10_to_62(_10num, defaultDigit);
String[] digitalTempArr = _10_62code.split("");
String[] digitalArr = new String[defaultDigit];
//补位检测
digitalArr = doComplement(digitalTempArr);
//保存单独位值
String[] singleDigital = new String[defaultDigit];
for (int i = 0; i < digitalArr.length; i++)
singleDigital[i] = digitalArr[i];
//进位开关
boolean[] singleCarryup = new boolean[defaultDigit];
int carryupLength = singleCarryup.length;
for (int i = 0; i < carryupLength; i++)
singleCarryup[i] = false;
//进位思想主要逻辑递归代码
singleDigital = recursiveNext(singleDigital, singleCarryup, 1);
//拼接单独位值
StringBuffer tmpBuff = new StringBuffer();
for (String tmp : singleDigital)
tmpBuff.append(tmp);
return tmpBuff.toString();
}
/**
* 检索值在数制表中的下标
*
* @param binaryValue
* @return 下标
*/
private int indexOfDigitalsystemtable(String binaryValue) {
int sourceIndex = -1;
for (int i = 0; i < DIGITALMETER_LENGTH; i++) {
if (binaryValue.equals(digitalsystemtable[i])) {
sourceIndex = i;
break;
}
}
return sourceIndex;
}
/**
* 判断是否是合规串码
*
* @param currentCodeStr 串码
* @return
*/
private boolean filterCharacter(String currentCodeStr) {
boolean isCompliance = true;
String[] digitalTempArr = currentCodeStr.split("");
for (int i = 0; i < digitalTempArr.length; i++) {
if (indexOfDigitalsystemtable(digitalTempArr[i]) < 0) {
isCompliance = false;
break;
}
}
return isCompliance;
}
/**
* 测试用例
*
* @param args
*/
public static void main(String[] args) throws InterruptedException {
CombinationCodeV4 combinationNumber = new CombinationCodeV4();
//DEMO_TEST1
/*String initCode = "0000";
int count = 0;
count++;
long startTime = System.currentTimeMillis();
System.out.println(initCode);
while (!initCode.equals("ZZZZ")) {
initCode = combinationNumber.generateNextCode(4, initCode);
count++;
System.out.println(initCode);
}
long endTime = System.currentTimeMillis();
System.out.println("count=" + count + ",耗时" + (endTime - startTime) + "ms");*/
//DEMO_TEST2
/*System.out.println(combinationNumber.generateNextCode(5, "0000"));
System.out.println(combinationNumber.generateNextCode(5, "ahzz"));
System.out.println(combinationNumber.generateNextCode(5, "YYYY"));
System.out.println(combinationNumber.generateNextCode(5, "ZZYZ"));
System.out.println(combinationNumber.generateNextCode(5, "ZZZY"));
System.out.println(combinationNumber.generateNextCode(5, "ZZZZ"));
System.out.println(combinationNumber.generateNextCode(5, "ZZZZZZZZZZ"));*/
//DEMO_TEST3
/*System.out.println(combinationNumber.generateNextCode(10, "000"));
System.out.println(combinationNumber.generateNextCode(10, "00"));
System.out.println(combinationNumber.generateNextCode(10, "0"));
System.out.println(combinationNumber.generateNextCode(10, ""));
System.out.println(combinationNumber.generateNextCode(10, "000-"));
System.out.println(combinationNumber.generateNextCode(10, "-00-"));
System.out.println(combinationNumber.generateNextCode(10, "0-0-"));
System.out.println(combinationNumber.generateNextCode(10, "--0-"));
System.out.println(combinationNumber.generateNextCode(10, "----"));
System.out.println(combinationNumber.generateNextCode(10, "ZZHZAA"));*/
//DEMO_TEST4
/*String initCode = "0000";
int count = 0;
count++;
long startTime = System.currentTimeMillis();
System.out.println(initCode);
while (!initCode.equals("ZZZZZZZZZZ")) {
initCode = combinationNumber.generateNextCode(10, initCode);
count++;
System.out.println(initCode);
Thread.sleep(100);
}
long endTime = System.currentTimeMillis();
System.out.println("count=" + count + ",耗时" + (endTime - startTime) + "ms");*/
//DEMO_TEST4_2
String initCode = "0";
int count = 0;
count++;
long startTime = System.currentTimeMillis();
System.out.println(initCode);
while (!initCode.equals("ZZZZ")) {
initCode = (String) combinationNumber.next(4);
count++;
System.out.println(initCode);
Thread.sleep(100);
}
long endTime = System.currentTimeMillis();
System.out.println("count=" + count + ",耗时" + (endTime - startTime) + "ms");
//DEMO_TEST4_3
/*int counter = 0;
long startTime = System.currentTimeMillis();
while (counter != 14776335) {
System.out.println(combinationNumber.next(4,counter));
counter++;
Thread.sleep(100);
}
long endTime = System.currentTimeMillis();
System.out.println("count=" + counter + ",耗时" + (endTime - startTime) + "ms");*/
/*//DEMO_TEST5
FileOutputStream fos = new FileOutputStream("/home/wangyetao/Documents/CombinationNumberV2Test_DEMO_TEST5.log");
String initCode = "0000";
int count = 0;
count++;
long startTime = System.currentTimeMillis();
System.out.println(combinationNumber.generateNextCode(10, initCode));
fos.write((initCode + "\n").getBytes());
while (!initCode.equals("ZZZZ")) {
initCode = combinationNumber.generateNextCode(10, initCode);
count++;
System.out.println(initCode);
fos.write((initCode + "\n").getBytes());
}
fos.close();
long endTime = System.currentTimeMillis();
System.out.println("count=" + count + ",耗时" + (endTime - startTime) + "ms");*/
}
}
进制转换工具类 BinaryConversion.java
/**
* Copyright (C), 2000-2021, XXX有限公司
* FileName: BinaryConversion
* Author: wangyetao
* Date: 21-10-23 21:58:38
* Description: 进制转换
* History:
* <author> <time> <version> <desc>
* 作者姓名 修改时间 版本号 版本描述
*/
package simple.callback.cryptographyalgorithm;
import java.util.Stack;
/**
* @ClassName: BinaryConversion
* @Description: 进制转换工具类
* @Author: wangyetao
* @Date: 21-10-23 21:58:38
*/
public class BinaryConversion {
private static char[] charSet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
/**
* 将10进制转化为62进制
*
* @param number
* @param length 转化成的62进制长度,不足length长度的话高位补0,否则不改变什么
* @return
*/
public static String _10_to_62(long number, int length) {
Long rest = number;
Stack<Character> stack = new Stack<Character>();
StringBuilder result = new StringBuilder(0);
while (rest != 0) {
stack.add(charSet[new Long((rest - (rest / 62) * 62)).intValue()]);
rest = rest / 62;
}
for (; !stack.isEmpty(); ) {
result.append(stack.pop());
}
int result_length = result.length();
StringBuilder temp0 = new StringBuilder();
for (int i = 0; i < length - result_length; i++) {
temp0.append('0');
}
return temp0.toString() + result.toString();
}
/**
* 将62进制转换成10进制数
*
* @param ident62
* @return
*/
private static String convertBase62ToDecimal(String ident62) {
int decimal = 0;
int base = 62;
int keisu = 0;
int cnt = 0;
byte ident[] = ident62.getBytes();
for (int i = ident.length - 1; i >= 0; i--) {
int num = 0;
if (ident[i] > 48 && ident[i] <= 57) {
num = ident[i] - 48;
} else if (ident[i] >= 97 && ident[i] <= 122) {
num = ident[i] - 97 + 10;
} else if (ident[i] >= 65 && ident[i] <= 90) {
num = ident[i] - 65 + 10 + 26;
}
keisu = (int) java.lang.Math.pow((double) base, (double) cnt);
decimal += num * keisu;
cnt++;
}
return String.format("%08d", decimal);
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//System.out.println("62System=" + _10_to_62(Integer.parseInt("35174605"), 5));
//System.out.println("10System=" + convertBase62ToDecimal("2NaWL"));
System.out.println("62System=" + _10_to_62(Integer.parseInt("14776335"), 4));
System.out.println("10System=" + convertBase62ToDecimal("ZZZZ"));
}
}
在此记录与总结,2021年 10月 24日 星期日 10:39:19 CST。