201709-3 CCF-CSP JSON查询 满分题解(两种代码解法)+ 解题思路

问题描述

在这里插入图片描述

实现技巧

这种需要嵌套定义并且类型不一时,可以用变量区分变量类型
结构体里不能嵌套unordered_map,可以嵌套map
对于多个函数操作一个字符串,可以将指针加引用,相当于指针跟着函数的操作移动,不需要再额外增加形参记录当前指针位置
反斜杠需要用//
使用未定义函数需要申明,不需要变量名
在选择结构中,如果该部分代码太长,也拎出来写,这样使得选择结构清晰易读,逻辑清晰
会多次用到的部分,使用函数来表示
不能直接赋值,会出错(该结构体的嵌套结构体赋给该结构体时。。maybe)
erase删除后,字符会左移,原来的下一个字符会变成当前这个字符,处理的时候要考虑到这个问题
答案特判输出时,询问情况应考虑全面

解题思路

  • 采用 map < string, node >进行存储,node是结构体,可以是string,也可以是嵌套的map < string, node >
  • 首先先将内容存储下来,全部存成一行,先提出所有多余的空格
  • 从{后的第一个字符开始递归处理对象
  • 处理键值对,若值为对象,递归处理
  • 将查询根据.进行分隔,用queue进行存储,如果不是最后一项,则更新查询的对象,如果是最后一项,则输出答案
  • 代码1和代码2解题思路差不太多,代码2多用函数封装,更简洁

代码实现1 :条例清晰版本

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>

using namespace std;

struct node
{
    bool is_obj; //这个节点是否是对象
    string val; //字符串的值
    map <string, node> obj; //对象
};

map <string, node> res; //只能用map,不能用unordered_map

void workBlank(string &str) //去除多余的空格
{
    string t;
    for (int i = 0; i < str.size(); i ++)
    {
        if (str[i] != ' ') t += str[i]; //只要不是空格的字符就要
    }
    str = t;
}

map <string, node> Object(string str, int &i)
{
    map <string, node> obj;
    
    if (str[i] == '}') //如果是空对象
    {
        i ++;
        return obj;
    }
    
    for (; i < str.size();)
    {
        if (str[i] == '"') //这一定是键值对的key的第一个引号
        {
            //处理key
            int j = i + 1; //指向"后一位
            string key;
            while (j < str.size() && str[j] != '"') //结束是j等于"
            {
                if (str[j] != '\\') key += str[j];
                else key += str[ ++ j]; //加上\后面那位
                j ++;
            }
            
            //处理value
            i = j + 2; //i指向冒号后面一位
            if (str[i] == '"') //值为string
            {
                int j = i + 1; //“后的第一个字符
                string value;
                while (j < str.size() && str[j] != '"') //结束是j等于"
                {
                    if (str[j] != '\\') value += str[j];
                    else value += str[ ++ j]; //加上\后面那位
                    j ++;
                }
                obj[key].is_obj = false;
                obj[key].val = value;
                i = j + 1; //i指向"后一位,可能是,或者}
            }
            else //值为对象
            {
                i ++; //i指向{后一位进入递归
                obj[key].is_obj = true;
                obj[key].obj = Object(str, i); //返回时j指向}后一位,可能是,或者}
            }

            if (str[i] == ',')
            {
                i ++; //i指向"
                continue;
            }
            else //只有可能是}
            {
                i ++; //返回时j指向}后一位,可能是,或者}
                //cout << str[i];
                return obj;
            }
        }
    }
}

queue <string> pushin(string str)
{
    queue <string> res;
    for (int i = 0; i < str.size();)
    {
        int k = str.find('.', i);
        if (k == -1) //后面没有.
        {
            res.push(str.substr(i));
            break;
        }
        else
        {
            res.push(str.substr(i, k - i));
            i = k + 1; //i指向.后一位
            continue;
        }
    }
    return res;
}

int main()
{
    int n, m;
    cin >> n >> m;

    string str;
    getchar();
    while (n --)
    {
        string t;
        getline(cin, t);
        str += t; //将所有内容拼接成一行
    }

    workBlank(str); //去除多余的空格

    //cout << str;
    int pos = 1;
    res = Object(str, pos); //递归处理对象,从{下一位开始

    //查询
    while (m --)
    {
        cin >> str;
        queue <string> q = pushin(str); //根据.进行分隔询问

        map <string, node> tmp1 = res;
        while (q.size())
        {
            string key = q.front();
            if (tmp1.count(key) == 0)
            {
                //for (auto x : tmp1) cout << x.first << endl;
                puts("NOTEXIST");
                break;
            }
            if (q.size() == 1) //查询的最后一项
            {
                if (tmp1[key].is_obj) puts("OBJECT");
                else cout << "STRING" << " " << tmp1[key].val << endl;
            }
            else //更新查询的对象
            {
                if (tmp1[key].is_obj == false) //如果该value不是对象,说明查询失败,因为这项不是最后一项,一定是对象
                {
                    puts("NOTEXIST");
                    break;
                }
                else
                {
                    map <string, node> tmp2 = tmp1[key].obj;
                    tmp1 = tmp2;
                }
            }
            q.pop();
        }
    }
    return 0;
}

代码实现2 :最短代码版本

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>

using namespace std;

//这种需要嵌套定义并且类型不一时,可以用变量记录变量类型
struct Obj
{
    int type; //1为str, 2为obj
    string str;
    Obj(){}
    Obj(string t)
    {
        type = 1;
        str = t;
    }
    //结构体里不能嵌套unordered_map,可以嵌套map
    map <string, Obj> kv; //对象中的key-value对
};

//会多次用到的部分,使用函数来表示
string work_str(string &str, int &pos)
{
    pos ++; //滤过'"'
    string s;
    while (pos < str.size() && str[pos] != '\"')
    {
        if (str[pos] == '\\') s += str[pos + 1], pos += 2; //反斜杠需要用//
        else s += str[pos ++];
    }
    pos ++; //滤过'"'
    return s;
}

//使用前需要申明,不需要变量名
Obj work_obj(string &, int &);

//在选择结构中,如果该部分代码太长,也拎出来写,这样使得选择结构清晰易读,逻辑清晰
void work_kv(Obj &thisobj, string &str, int &pos)
{
    string key = work_str(str, pos);
    pos = str.find(':', pos); //找到':'位置
    while (str[pos] != '\"' && str[pos] != '{') pos ++;
    if (str[pos] == '\"') thisobj.kv[key] = Obj(work_str(str, pos));
    else thisobj.kv[key] = work_obj(str, pos);
}

Obj work_obj(string &str, int &pos)
{
    Obj thisobj;
    thisobj.type = 2;
    while (pos < str.size() && str[pos] != '{') pos ++;
    pos ++; //过滤掉'{'
    while (pos < str.size() && str[pos] != '}')
    {
        if (str[pos] == '\"') work_kv(thisobj, str, pos);
        else pos ++;
    }
    pos ++; //滤过'}'
    return thisobj;
}

void query(Obj obj, vector <string> qs)
{
    for (auto q : qs)
    {
        if (obj.type == 1 || obj.kv.count(q) == 0)
        {
            puts("NOTEXIST");
            return ;
        }
        
        // 不能直接赋值,会出错(该结构体的嵌套结构体赋给该结构体时。。maybe)
        Obj t = obj.kv[q];
        obj = t;
    }
    
    if (obj.type == 1) printf("STRING %s\n", obj.str.c_str());
    else puts("OBJECT");
}

int main()
{
    int n, m;
    cin >> n >> m;
    getchar();
    
    string str, tmp;
    while (n --)
    {
        getline(cin, tmp);
        str += tmp; //将整个对象合并成一个串
    }
    
    int p = 0; //串的起始位置

    auto mainobj = work_obj(str, p); //处理最外层的对象
    
    while (m --)
    {
        getline(cin, tmp);
        vector <string> qs; //存储每一个查询
        for (int i = 0; i < tmp.size(); i ++)
        {
            int j = i + 1;
            while (j < tmp.size() && tmp[j] != '.') j ++;
            qs.push_back(tmp.substr(i, j - i));
            i = j;
        }
        query(mainobj, qs);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只可爱的小猴子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值