poj 4093:倒排索引查询

poj 4093:倒排索引查询

题目:

总时间限制: 
1000ms 
内存限制: 
131072kB
描述

现在已经对一些文档求出了倒排索引,对于一些词得出了这些词在哪些文档中出现的列表。

要求对于倒排索引实现一些简单的查询,即查询某些词同时出现,或者有些词出现有些词不出现的文档有哪些。

输入
第一行包含一个数N,1 <= N <= 100,表示倒排索引表的数目。

接下来N行,每行第一个数ci,表示这个词出现在了多少个文档中。接下来跟着ci个数,表示出现在的文档编号,编号不一定有序。1 <= ci <= 1000,文档编号为32位整数。

接下来一行包含一个数M,1 <= M <= 100,表示查询的数目。

接下来M行每行N个数,每个数表示这个词要不要出现,1表示出现,-1表示不出现,0表示无所谓。数据保证每行至少出现一个1。

输出
共M行,每行对应一个查询。输出查询到的文档编号,按照编号升序输出。

如果查不到任何文档,输出"NOT FOUND"。

样例输入
3
3 1 2 3
1 2
1 3
3
1 1 1
1 -1 0
1 -1 -1
样例输出
NOT FOUND
1 3
1

解题方案

我们先考虑两个子问题

1.求出两个有序递增数组的交集,并集,补集

我使用的是归并排序思想,只不过取得元素不同而已

2.求出多个有序递增数组的交集,并集

第一问题是这个问题的子问题,同时使用归并思想去做,如同擂台赛一样,每一个数组如同一个选手去争冠军

好了,子问题解决完毕,我们看看poj题目

1)对每一个索引表排序

2)对每一组查询,找出需要出现的文档号集合 wanted_list 和 不出现的文档号集合 not_wanted_list(这两个问题分别是上述第二个子问题求多个数组的交集,并集问题)

3)求出wanted_list 相对 not_wanted_list的补集即可

代码c++如下

#include <iostream>
#include <list>
#include <algorithm>
#include <map>
#include <fstream>
using namespace std;

class Node
{
public:
	int word_id;
	int bit;
};

int compare(const void * a,const void * b)
{
	return *(int*)a - *(int *)b;
}

void print_list(list<int> mylist);
list<Node> initialize_list(int **search,int row,int N,bool need);
list<int> sub_data(list<int> wanted_list,list<int> not_wanted_list);
list<int> find_same_need(list<Node> mylist,int ** data,const int length);
list<int> find_same_not_need(list<Node> mylist,int ** data,const int length);
void read_data(int ** &data,int ** & search,int &M,int &N);

int main()
{
	int ** data;
	int ** search;
	int M,N;
	list<int> wanted_list;
	list<int> not_wanted_list;
	list<Node> wanted_node_list;
	list<Node> not_wanted_node_list;
	list<int> result;
	read_data(data,search,M,N);

	for( int i=0;i<M;i++ )
	{
		wanted_node_list = initialize_list(search,i,N,true);
		not_wanted_node_list = initialize_list(search,i,N,false);
		wanted_list = find_same_need(wanted_node_list,data,N);
		not_wanted_list = find_same_not_need(not_wanted_node_list,data,N);
		result = sub_data(wanted_list,not_wanted_list);
		print_list(result);
	}
	system("pause");
	return 0;

}

list<int> find_same_need(list<Node> mylist,int ** data,const int length)
{
	list<int> result;
	bool same ;
	list<Node>::iterator min_node;
	int min_article_id;

	while( true )
	{
		// 1. 检查当前文档号是否是一样的
		same = true;
		Node one = mylist.front();
		for(list<Node>::iterator node = mylist.begin();node != mylist.end(); node++)
		{
			if( data[one.word_id][one.bit] != data[node->word_id][node->bit] )
			{
				same = false;
				break;
			}
		}

		// 2. 结果如果不相同时,则需要增加最小的
		if( ! same )
		{
			min_article_id = INT_MAX;
			for(list<Node>::iterator node = mylist.begin();node != mylist.end(); node++)
			{
				if( data[node->word_id][node->bit] < min_article_id )
				{
					min_article_id = data[node->word_id][node->bit];
					min_node = node;
				}
			}
			min_node->bit ++;
			// 已经得到所有结果
			if( min_node->bit > data[min_node->word_id][0] )
				return result;
		}

		// 3. 存储一个结果
		else
		{
			result.push_back( mylist.front().bit );
			for (list<Node>::iterator node = mylist.begin(); node != mylist.end(); node++)
			{
				node->bit ++;

				// 已经得到所有结果
				if( node->bit > data[node->word_id][0] )
					return result;
			}
		}
	}
}

list<int> find_same_not_need(list<Node> mylist,int ** data,const int length)
{
	map<int,bool> myamp;
	list<int> result;
	for(list<Node>::iterator it = mylist.begin();it != mylist.end() ;it++)
	{
		while(it->bit <= data[it->word_id][0])
		{
			if( myamp.find(data[it->word_id][it->bit]) == myamp.end() )
			{
				myamp.insert(make_pair(data[it->word_id][it->bit],true));
			}
			it->bit ++;
		}
	}
	for(map<int,bool>::iterator it = myamp.begin();it!=myamp.end();it++)
	{
		result.push_back(it->first);
	}
	return result;
}

list<int> sub_data(list<int> wanted_list,list<int> not_wanted_list)
{
	list<int> result;
	list<int>::iterator wanted_it,not_wanted_it;
	wanted_it = wanted_list.begin();
	not_wanted_it = not_wanted_list.begin();
	while( wanted_it!= wanted_list.end() && not_wanted_it != not_wanted_list.end() )
	{
		if( *wanted_it < *not_wanted_it )
		{
			result.push_back(*wanted_it) ;
			wanted_it++;
		}
		else if( *wanted_it > *not_wanted_it )
		{
			not_wanted_it++;
		}
		else
		{
			wanted_it++;
			not_wanted_it++;
		}
	}
	while(wanted_it != wanted_list.end())
	{
		result.push_back(*wanted_it);
		wanted_it++;
	}
	return result;
}

list<Node> initialize_list(int **search,int row,int N,bool need)
{
	list<Node> result;
	Node node;
	if( need )
	{
		for( int i=0;i<N;i++ )
		{
			if( search[row][i] == 1 )
			{
				node.word_id = i;
				node.bit = 1;
				result.push_back( node );
			}
		}
	}
	else
	{
		for( int i=0;i<N;i++ )
		{
			if( search[row][i] == -1 )
			{
				node.word_id = i;
				node.bit = 1;
				result.push_back( node );
			}
		}
	}
	return result;
}

void print_list(list<int> mylist)
{
	if(mylist.size() > 0)
	{
		for(list<int>::iterator it=mylist.begin();it != mylist.end();it++)
		{
			cout<<*it<<" ";
		}
	}
	else cout<<"NOT FOUND";
	cout<<endl;
}

void read_data(int ** &data,int ** & search,int &M,int &N)
{
	ifstream reader;
	reader.open("data.txt");
	reader>>N;
	data = new int* [N];
	int m;
	for(int i=0;i<N;i++)
	{
		reader>>m;
		data[i] = new int[m+1];
		data[i][0] = m;
		for(int j=1;j<m+1;j++)
		{
			reader>>data[i][j];
		}
		qsort(data[i]+1,data[i][0],sizeof(int),compare);
	}

	reader>>M;
	search = new int * [M];
	for(int i=0;i<M;i++)
	{
		search[i] = new int[N];
		for(int j =0;j<N;j++)
		{
			reader>>search[i][j];
		}
	}
	reader.close();
}

数据测试 data.txt

3
3 1 2 3
1 2
1 3
3
1 1 1
1 -1 0
1 -1 -1

程序结果

时间: 2024-09-18 23:45:11

poj 4093:倒排索引查询的相关文章

poj4093:倒排索引查询

总时间限制: 1000ms 内存限制: 131072kB 描述 现在已经对一些文档求出了倒排索引,对于一些词得出了这些词在哪些文档中出现的列表. 要求对于倒排索引实现一些简单的查询,即查询某些词同时出现,或者有些词出现有些词不出现的文档有哪些. 输入 第一行包含一个数N,1 <= N <= 100,表示倒排索引表的数目. 接下来N行,每行第一个数ci,表示这个词出现在了多少个文档中.接下来跟着ci个数,表示出现在的文档编号,编号不一定有序.1 <= ci <= 1000,文档编号为

elasticsearch 查询 query

对于 类型是 text的字段,并且分析器指明是ik_max_word的会建立倒排索引 查询的分类: match查询:  会自动转换大小写,会分词, term查询: 不会转换和分词,只能值匹配 terms查询: 可以给字段值传入数组, 这里有没有分词呢??????????应该和term一样的只会值匹配吧,要不为啥叫terms,待验证 控制查询的数量,  from,和size属性指明,可以用来分页 match_all: 搜索索引下的所有type match_phrase: 满足分词后的所有词, sl

在不清楚数据表字段数据分布的情况下,应该创建什么类型的索引?

在讨论之前,先看看关系型数据库常见的索引类型: 1.位图索引,适用于该字段重复数据很多的情况: 2.B+树索引,适用于该字段重复数据不多的情况. 在不清楚数据表字段数据分布的情况下,应该创建什么类型的索引?个人觉得以上两种都不太适用,可以尝试使用第3类的索引: 3.倒排索引,在搜索引擎使用较多,适用于大多数的情况. 使用普通的文本文件格式存储倒排索引,格式为: value:rowid(行标识码),字段值对应value,rowid对应该行的标识码. 要注意的是,在创建倒排索引时,倒排索引的key需

●ZOJ 2112 Dynamic Rankings

●赘述题目 对于一个长为n(n<50000)的序列(序列中的数小于1000000000),现有如下两种指令: Q a b c:询问区间[a,b]中第c小的数. C p b:将序列中的从左往右数第p个数改成b. ●题解 (整体二分应该可以做吧...但写不来了) 主席树+树状数组套线段树维护. 本题和POJ 2104 K-th Number相比,多了一个修改操作,但真的做得我心累. 看看POJ 2104 的查询函数: 查询区间到底是往左还是往右,这决于tmp与k大小关系.但本题因为有修改操作,导致上

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

Lucene4.6 把时间信息写入倒排索引的Offset偏移量中,并实现按时间位置查询

有个新的技术需求,需要对Lucene4.x的源码进行扩展,把如下的有时间位置的文本写入倒排索引,为此,我扩展了一个TimeTokenizer分词器,在这个分词器里将时间信息写入 偏移量Offset中.扩展了一个Filter,最后查询时通过filter把时间信息传进去过滤想要的时间范围之内的结果. Lucene倒排索引中分好的词有两个偏移量一个是按字符的偏移量(BeginOffset和EndOffset)另一个是以分词(Term)为一个单元的position,每增加一个词position加1,如果

POJ 2155 二维线段树 经典的记录所有修改再统一遍历 单点查询

本来是想找一个二维线段树涉及懒惰标记的,一看这个题,区间修改,单点查询,以为是懒惰标记,敲到一半发现这二维线段树就不适合懒惰标记,你更新了某段的某列,但其实其他段的相应列也要打标记,但因为区间不一样,又不好打...也可能是我这是在套用一维线段树的思想,还有更好的二维线段树懒惰标记方法 反正到现在我还没搞定二维线段树的懒惰标记,因为这道题不用懒惰标记,因为是二进制序列,区间修改仅限于翻转操作,那就只要记录每次操作,最后查询的时候从上往下把所有修改都来上一遍,就可以了.就类似于树状数组的第二种用法,

POJ 2763 (树链剖分+边修改+边查询)

题目链接:http://poj.org/problem?id=2763 题目大意:某人初始在s点.有q次移动,每次移动沿着树上一条链,每经过一条边有一定花费,这个花费可以任意修改.问每次移动的花费. 解题思路: 树链剖分基础题.每次Q之后改变一下s. 线段树记录的是边权.方法是对于一条边(u,v),边权值加在dep比较大的那一端. 链查询(边)和 链查询(点)在轻链时略有不同. 注意本题使用vector邻接表存图是会TLE的,应该使用链式前向星.树链剖分中使用链式前向星是基本要求. #inclu

poj 2155- Matrix (树状数组,二维,更新区间,查询单点)

Matrix Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j]