连续的K=V的字符串,每个K=V之间用","分隔,V中可嵌套K=V的连续字符串结构,例如“ key1=value1,key2=value2,key3=[key4=value4,key5=value5,key6=[key7=value7]],key8=value8 请编写如下函数,给定字符串,输出嵌套结构的HashMap HashMapparse(String input) { ... } 附:生成连续字符串结构的代码,通过调整嵌套最大层级和size数组大小,控制生成的字符串大小
static int count=0;//key计数器
/**
* 生成测试字符串
* @param ceng 嵌套最大层级
* @return
*/
public static String createString(int ceng){
if(ceng>5000)return "";
String[] size=new String[10000]; //每层结构一共存在键值对的数量
for(int i=0;i0){ //有层级
String key="key"+(++count);
size[i]=key+"=["+createString(++ceng)+"]";
}else{
String key="key"+(++count);
size[i]=key+"=value"+count;
}
}
return String.join(",",size);
}
只处理当前字符串第一个嵌套体位置的前面普通键值对,将第一个嵌套体内容递归处理,将第一个嵌套体后面剩余的字符串递归处理
HashMap parse(String input){
HashMap hashMap=new HashMap<>();
char[] chars=input.toCharArray();
int keyStart=0;
int start=-1;//[位置
int end=-1;//]位置
int stack=0;//栈计数器
for (int i=0;i0;j--){
if(chars[j]==','){
keyStart=j+1;
break;
}
}
}
}else if(chars[i]==']'){
if(stack==1){
end=i;
break;
}
stack--;
}
}
String[] keyValueArray=new String[0];
if(start>-1){
//这里处理前半截
if(keyStart-1>=0){
keyValueArray=input.substring(0,keyStart-1).split(",");
}
//发现有[] , 递归处理
String temp=input.substring(start,end);
hashMap.put(input.substring(keyStart,start-2),parse(temp));
//发现后面还有东西
if(end
依次将当前字符串中所有普通键值对进行处理,将所有遇到的嵌套体内容递归处理,减少递归次数,但逻辑更加复杂
HashMap parse(String input) {
HashMap hashMap = new HashMap<>();
char[] chars = input.toCharArray();
int kvStart = 0;//记录当前键值对的开始字段
int keyStart = 0;
int start = -1;//[位置
int end = -1;//]位置
int stack = 0;//栈计数器
for (int i = 0; i < chars.length; i++) {
if (chars[i] == ',' && stack == 0) {//stack=0,表示不在嵌套结构内,作为普通的键值对解析
String[] array = input.substring(kvStart, i).split("=");
hashMap.put(array[0], array[1]);
kvStart = i + 1;
}else if(i==chars.length-1&&chars[i] != ']'){//尾部处理:如果是普通的字符串,尾部肯定不是],作为普通键值对
String[] array = input.substring(kvStart, i+1).split("=");
hashMap.put(array[0], array[1]);
}else if (chars[i] == '[') {
stack++;
if (stack == 1) {//第一次嵌套开始
start = i + 1;//嵌套内容起始位置
for (int j = i; j > 0; j--) {
if (chars[j] == ',') {
keyStart = j + 1;//当前嵌套体的key起始字符位置
break;
}
}
}
} else if (chars[i] == ']') { //第一次嵌套结束
if (stack == 1) {
end = i;
hashMap.put(input.substring(keyStart, start - 2), parse(input.substring(start, end)));
i++;//跳过逗号
kvStart = i + 1;//下个键值对的起始位置
}
stack--;
}
}
return hashMap;
}
不用递归,但利用递归的思想,将递归的参数封装,并构建成队列,进行循环操作,模拟递归。
这样的好处是,递归方法栈容量有限。当递归时方法栈的参数越多,占用栈内存越大,总栈帧数量越小,自己定义的队列不受此限制
HashMap parse(String input) {
//根
HashMap root = new HashMap<>();
//初始化列表
List>> nodeList=new ArrayList<>();
nodeList.add( new Pair<>(input,root));
//处理列表元素
while (nodeList.size()>0){
//每次取出第一个元素
Pair> node=nodeList.get(0);
nodeList.remove(0);
HashMap hashMap=node.getValue();
String temp=node.getKey();
char[] chars = temp.toCharArray();
int keyStart = 0,start = -1,end = -1,stackCount = 0;//记录当前键值对的开始字段
for (int i = 0; i < chars.length; i++) {
if (chars[i] == ',' && stackCount == 0) {//stack=0,表示不在嵌套结构内,作为普通的键值对解析
String[] array = temp.substring(keyStart, i).split("=");
hashMap.put(array[0], array[1]);
keyStart = i + 1;
}else if(i==chars.length-1&&chars[i] != ']'){//尾部处理:如果是普通的字符串,尾部肯定不是],作为普通键值对
String[] array = temp.substring(keyStart, i+1).split("=");
hashMap.put(array[0], array[1]);
}else if (chars[i] == '[') {
stackCount++;
if (stackCount == 1) {//第一次嵌套开始
start = i + 1;//嵌套内容起始位置
for (int j = i; j > 0; j--) {
if (chars[j] == ',') {
keyStart = j + 1;//当前嵌套体的key起始字符位置
break;
}
}
}
} else if (chars[i] == ']') { //第一次嵌套结束
if (stackCount == 1) {
end = i;
HashMap child = new HashMap<>();
hashMap.put(temp.substring(keyStart, start - 2), child);//先存放嵌套对象的地址
nodeList.add(new Pair<>(temp.substring(start, end),child));//加入堆栈等待处理
i++;//跳过逗号
keyStart = i + 1;//下个键值对的起始位置
}
stackCount--;
}
}
}
return root;
}
测试结果:
测试字符串长度:617534
解法1时间:31,解法2时间:32,解法3时间:95测试字符串长度:617535
解法1时间:33,解法2时间:46,解法3时间:94
测试字符串长度:6817510
解法1时间:188,解法2时间:173,解法3时间:236测试字符串长度:6817510
解法1时间:206,解法2时间:141,解法3时间:255测试字符串长度:6817511
解法1时间:204,解法2时间:157,解法3时间:236
测试字符串长度:74577486
解法1时间:3582,解法2时间:3846,解法3时间:2293测试字符串长度:74577486
解法1时间:2387,解法2时间:3840,解法3时间:2685测试字符串长度:74577486
解法1时间:3354,解法2时间:2492,解法3时间:2312测试字符串长度:74577486
解法1时间:2970,解法2时间:3272,解法3时间:2727
数据量小的时候发现递归存在很大的优势,结构简单,执行快
数据量大的时候非递归显露出较大的优势,结构复杂,执行快
总结:实际情况下可以根据设置长度阈值,动态选择相应的解析算法