C++ 构建简单倒排索引


智能信息检索这门课的第一个上机实验:
问题表述如下:
1.对硬盘目录中的10个文本文件(doc01.txt~doc10.txt),在内存中建立倒排索引
2.构建索引系统,输入查询词,输出包含查询词的文档ID


思路

要构建倒排索引,首先我们对每个文档编号(设置ID),这里我们可以设置一个名为Doc的结构体,用于绑定文档和他的ID,然后将每个文档放入数组中,生成我们所需要构建倒排索引的文档集。(这里我们使用STL中的vector),之后进行最重要的构建倒排索引的操作(详细步骤见该模块说明),最后我们简单的写一个查询函数就完成我们的任务啦。


一、构建文档

1.给出我们要构建倒排的文档名

static vector<string> files={ 
"doc1.txt","doc2.txt", "doc3.txt",
"doc4.txt","doc5.txt", "doc6.txt", 
"doc7.txt","doc8.txt","doc9.txt","doc10.txt" };

2.建立文档结构体,保存其文档名和文档ID

struct Doc {
	string docName;//文档名
	int docID;//文档ID
	Doc() { docName = "", docID = -1; }
};

3.构建文档集

vector<Doc> Docs;//文档集
void makeDocs(vector<Doc> &Docs){//生成文档集
	Doc *doc = new Doc;
	//将文档依次编号,生成文档集
	for (int i = 0; i < files.size(); ++i) {
	doc->docName = files[i];
	doc->docID = 1+i;
	Docs.push_back(*doc);
	}
	delete doc;
}

3.显示我们构建的文档集(这是一个小小的附加功能)

void showDocs() {//显示文档集
	for (int i = 0; i <Docs.size(); ++i) {
		cout << "DocName: "<<Docs[i].docName << "\tdocID: " << Docs[i].docID<<endl;
	}
}

二、构建倒排索引

详细步骤见注释啊,笔者懒了:

map<string,set<int>> indexList;//倒排记录表
void index(vector<Doc> &Docs) {
	for (int i = 0; i < Docs.size(); ++i) {
		ifstream in(Docs[i].docName);//依次打开文档
		int ch;//用于扫描的字母
		string s;//获取到的单词
		map<string, set<int>>::iterator it;//用于判定词项是否在倒排记录表中
		if (in.is_open()) {
			while (!in.eof()) {//一次循环获取一个单词
				//找到第一个字母
				do {
					ch = in.get();//获取一个字符
					if (in.eof())break;//遇到文件尾则结束
				} while (!isalpha(ch));
				if (in.eof())break;//防止后面的空行而不能结束
				while (isalpha(ch)) {
					ch=tolower(char(ch));//将获取到的字母变为小写
					s += ch;//合成单词
					ch = in.get();
				}
				it = indexList.find(s);//判断s是否已经在倒排记录表中
				if (it != indexList.end()) {//如果s已经在全体倒排记录表中
					it->second.insert(i+1);//只将词项对应的文档编号加入倒排记录表
				}
				else {//s不在全体倒排记录表中
					set<int> pset{i+1};//s词项对应的文档编号放入set
					pair<string, set<int>> newTrem(s, pset);//新词项及其倒排记录表
					indexList.insert(newTrem);//将新词项及其倒排记录表加入全体倒排记录表
				}
				s.clear();//清空s,进行下一个单词的操作
			}

		}
		in.close();//关闭文件,以便进行下一个文档的到操作
	}
	cout << "倒排索引构建成功" << endl;
}

一个附加小功能(显示倒排记录表)

void showIndexList(const map<string, set<int>> indexList){
	for (auto c : indexList) {//显示倒排记录表
		cout << c.first<<"\t" ;
		for (auto c1 : c.second) {
			cout << c1 << " ";
		}
		cout << endl;
	}
}

三.查询

void query(string s) {//查询
	map<string, set<int>>::iterator it=indexList.find(s);//判断s是否在全体倒排记录表
	if (it!= indexList.end()) {//Yes
		cout << s << "\t"<<"出现的文档:";
		int length = it->second.size();
		for (auto c : it->second) {//输出该词项的倒排记录表
			cout << c << " ";
		}
		cout << endl;
	}
	else {//N0
		cout << s << "没有在文档中出现" << endl;
	}
}

main函数

int main() {
	makeDocs(Docs);
	showDocs();
	index(Docs);
	showIndexList(indexList);
	while (true) {
		cout << "请输入查询词:";
		string s;
		cin >> s;
		query(s);
		cout << endl;
	}
}

总结

笔者写该程序用到了,vector,set,map,pair等等STL的功能,set和map的底层都是红黑树,所以每次进行的查询,插入等操作时间复杂度都是灰常的低的。把代码从上到下copy一下就是源代码了,笔者很菜也,肝了很久,给个赞呗。

  • 43
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值