月模拟(四)——201809-3 元素选择器

在这里插入图片描述

题目背景

在这里插入图片描述

题目描述

在这里插入图片描述
在这里插入图片描述

输入输出

在这里插入图片描述

样例

在这里插入图片描述

Hints

在这里插入图片描述
在这里插入图片描述

解题思路

首先将每个元素处理为一个结构体node

  • 包含4个属性:级数(用点数/ 2表示名次,名次越高点数越小)、元素标签label、元素id属性,以及该节点的父亲节点。
  • 同时,对每个元素,结构体内编写选择器判定函数find(),和匹配函数nameIsSame(),对标签和id进行匹配。

当输入结构化文档的每个元素时

  • 在查找label索引位置时,可通过索引位置判断’.'的数目,确定该行的级数
  • 通过字符处理获得label和id(可没有id),且label标签名需要转为小写
  • 若该行级数不大于当前父节点的级数,则父节点向上查找,直到找到级数更小的元素,作为此元素的父节点,每个新元素加入后,作为当前的父节点。

每个选择器输入过程中,若为后代选择器,要根据空格区分,依次加入选择器向量slt(标签选择器输入时要注意转换为小写)。

选择过程中,对每行元素依次判别,先对slt中最后一个字符串进行匹配,若不满足直接返回,判断下一个元素;若满足,根据向量中字符串的数目再判断该选择器的类型

  • 若该选择器为标签选择器或id选择器,直接加入结果中
  • 若为后代选择器,遍历文档依次查找该元素的父节点,判断父节点是否依次匹配slt向量前面字符串代表的标签或id,若向量中所有字符串全部匹配完毕,说明该元素满足次此选择器,加入结果

代码

#include<iostream>
#include<string>
#include<vector>
using namespace std;

struct node {
	string label,id;
	node *parent;
	int line;
	int level = -1;
	
	bool nameIsSame(string &name) {
		if (name[0]== '#') return name == id;
		else return name == label;
	}
	void find(vector<string> &slt, vector<int> &lines_No) {
		if (!nameIsSame(slt.back())) return;
		int slt_index = slt.size() - 2;
		node *p = this->parent;
		while (p&&slt_index>=0) {
			if (p->nameIsSame(slt[slt_index])) slt_index--;
			p = p->parent;
		}
		if (path_index == -1) {
			lines_No.push_back(line);
		}
	}
};

node *datas[100];
char s[100];

int main() {
	int n, m;
	cin>>n>>m; 
	getchar();
	node *root = new node();
	node *p = root;
	for (int i = 0; i < n; ++i) {
		getline(cin, s);
		int label_index = 0;
		char c;
		while (c = s[label_index++]) {
			if (c != '.') break;
		}
		int level = label_index / 2;
		while (level <= p->level) p = p->parent;
		string label;
		label.push_back(c < 'a' ? c + 32 : c);//转换为小写 
		while (c = s[label_index++]) {
			if (c == ' ') break;
			label.push_back(c < 'a' ? c + 32: c);
		}
		string id;
		while (c = s[label_index++]) {
			id.push_back(c);
		}
		
		node *new_node = new node();
		new_node->level = level;
		new_node->line = i + 1;
		new_node->label = label;
		new_node->id = id;
		new_node->parent = p;
		datas[i] = new_node;
		p = new_node;
	}
	for (int i = 0; i < m; ++i) {
		vector<string> slt;
		getline(cin,s);
		int index = 0;
		char c;
		string tmp;
		while (c = s[index++]) {
			if (c == ' ') {
				slt.push_back(tmp);//选择器加入vector 
				tmp = "";
			}
			else {
				if (c=='#'||(tmp.size() > 0 && tmp[0]=='#')) //id大小写敏感 
					tmp.push_back(c);
				else tmp.push_back(c < 'a' ? c + 32 : c);//label大小写不敏感 
			}
		}
		vector<int> lines_No;
		slt.push_back(tmp);
		for (int j = 0; j < n; ++j) {
			datas[j]->find(slt, lines_No);
		}
		int len = lines_No.size();
		cout << len;
		for (int j = 0; j < len; ++j) {
			cout << ' ' << lines_No[j];
		}
		cout << endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值