程序设计思维与实践 月模拟题 元素选择器

元素选择器

背景:

在这里插入图片描述

描述:

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

输入:

在这里插入图片描述

输出:

在这里插入图片描述

样例:

输入:

11 5
html
..head
....title
..body
....h1
....p #subtitle
....div #main
......h2
......p #one
......div
........p #two
p
#subtitle
h3
div p
div div p

输出:

3 6 9 11
1 6
0
2 9 11
1 11

想法:

学习大佬的代码,学习大佬的思想,学习大佬的组织形式(膜)。
读题后大体上属于搜索题,题目中“整体上形成树的结构”暗示可以用树结构组织HTML文件,这里将每一行抽象成一个树顶点(没想到)。
1,设计数据结构:
每一行当做一个顶点,name 和 tag分别记录标签和id,level记录行的级数也可以理解为层数,还有一个指向上级的parent指针。
2,建树过程:
在栈中保存父子结构,插入新的节点按照level找到其直接上司。同时不忘最后parents.push(now);//压入parent栈 nodes.push_back(now);//加入节点vector 。
3,查询过程:
查询过程先将待查询内容分词到sel中,按sel从后往前先查询。如果全都查到,说明找到合法元素,否则不合法。这里的check函数中id大小写敏感,直接判等。标签大小写不敏感,逐个字符转化为小写tolower(s[i])再判等(学到了orz都不知道有这个函数)。

大佬们在读题的过程中就有了思路,比如读到树结构,立马能将HTML文档抽象成树,节点也抽象好了。一读到大小写敏感与否就想到可能用到tolower(),可能有其他的比较方法,但是这样就显得主体结构比较简单,思维不会再大小写上打转。

代码:

#include <iostream>
#include <fstream>//c++文件操作集合 
#include <vector>
#include <stack>
#include <sstream>//c++流操作 

using namespace std;

struct node
{
    
    
	string name,tag;//标签和属性; 
	int level;//级数; 
	node* parent;//父节点; 
	node(string n,string t,int l):name(n),tag(t),level(l),parent(0) {
    
    }
}; 

void divide(const string& line,vector<string>& sel)
{
    
    
	sel.clear();
	string token;
	token.clear();
	for(int i=0;i<line.size();i++)
	{
    
    
		if(line[i]==' ')
		{
    
    //遇到空格处理; 
			sel.push_back(token);
			token.clear();
		}
		else token+=line[i];//逐个写入字符; 
	}
	//处理最后一个; 
	sel.push_back(token);
}


bool check(node* t,const string& s)
{
    
    
	if(s[0]=='#') return s==t->tag;//id大小写敏感,直接判等; 
	// 
	if(s.size() != t->name.size()) return false;
	
	for(int i=0;i<s.size();i++)
	{
    
    //标签大小写不敏感,转换为小写判等; 
		if(tolower(s[i]) != tolower(t->name[i])) return false;
	}
	return true;
}

int main()
{
    
    
	int n,m;
	scanf("%d%d",&n,&m);
	
	vector<node*> nodes;
	nodes.clear();
	stack<node*> parents;
	while(!parents.empty()) parents.pop();
	
	string line;getline(cin,line);
	while(n--)
	{
    
    //输入并构建树结构; 
		getline(cin,line);
		int level=0;
		
		while(line[level]=='.') level++;
		stringstream ss(line.substr(level));//返回选定子串;
		//区分与substring(start,end(不包含))的用法; 
		string name,tag;
		ss>>name>>tag;
		//cout<<name<<' '<<tag<<endl;
		node* now=new node(name,tag,level);
 
		if(!parents.empty())
		{
    
    
			node* p;
			while(p=parents.top(), p->level >= level)
			{
    
    //找到level的上一级; 
				parents.pop();
			}
			now->parent=p;//p的level恰好比now小,是now的直接上级; 
			//cout<<now->name<<"'s parent is "<<now->parent->name<<endl;
		}
		parents.push(now);//压入parent栈 
		nodes.push_back(now);//加入节点vector 
	} 
	
	vector<int> ans;
	vector<string> sel;
	
	while(m--){
    
    //查询; 
		getline(cin,line);
		divide(line,sel);	//拆分 
		ans.clear();
		
		for(int i=0;i<nodes.size();i++)
		{
    
    //遍历节点; 
			int sl=sel.size()-1;//最后一个索引; 
			if(check(nodes[i],sel[sl]))
			{
    
    
				node* t=nodes[i]->parent;
				sl--;
				while(t && sl>=0)
				{
    
    //向上匹配; 
					if(check(t,sel[sl])) sl--;
					t=t->parent;
				}
				if(sl==-1) ans.push_back(i+1);//第几个,而不是索引; 
			}
			
		}
		printf("%d ",ans.size());
		for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
		if(m!=0) printf("\n");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44080131/article/details/106565579