数据结构的最终目的是提高数据的处理速度,索引是为了加快查找速度而设计的一种数据结构,索引就是把一个关键字与它对应的记录相关联的过程,一个索引表由若干个索引项构成,每个索引项至少包含关键字和其对应的记录在存储器中的位置等信息。索引技术是组织大型数据库以及磁盘文件的一种重要技术。
索引按结构分可以分为线性索引、树形索引和多级索引。这里只介绍线性索引,线性索引就是将索引项集合组织为线性结构,也为索引表。线性索引有三种:稠密索引、分块索引和倒排索引。
1、稠密索引
稠密索引是指在线性索引中,将数据集中的每个记录对应一个索引项。对于稠密索引这个索引表来说,索引项一定是按照关键码有序的排列。索引项有序也就意味着查找关键字时,可以用到折半、插值、斐波那契等有序查找算法,大大提高了效率。稠密查找缺点是如果数据集非常大,比如上亿,那也就意味着索引也得同样的数据集长度规模,对于内存有限的计算机来说,可能就需要反复去访问磁盘,查找性能反而大大下降了。
2、分块索引
稠密索引因为索引项与数据集的记录个数相同,所以空间代价很大。为了减少索引项的个数,我们可以对数据集进行分块,使其分块有序,然后再对每一块建立索引项,从而减少索引项的个数。分块有序是把数据集的记录分成了若干块,并且这些块需要满足两个条件:块内无序、块间有序。对于分块有序的数据集,将每块对于一个索引项,这种索引方法叫做分块索引。分块索引的索引项结构分三个数据项:最大关键码、块内记录个数、指向块首数据元素的指针。分块索引表的查找,分两步进行:第一步在分块索引表中查找要查关键字所在的块,第二步根据块首指针找到相应的块并在块内顺序查找关键字。分块索引的效率是,比顺序查找的O(n)快了不少,但比折半查找的慢,因此在块间查找时可以应用折半、插值查找等手段。分块查找普遍应用于数据库查找等技术的应用中。
3、倒排索引
倒排索引就是将文档中的单词作为关键字,然后建立单词与文档的映射关系。倒排索引是现代搜索引擎的核心技术之一,其核心目的是将从大量文档中查找包含某些词的文档集合这一任务用O(1)或者O(logn)的时间复杂度完成,其中n为索引中的文档数目。也就是说,利用倒排索引技术,可以实现与文档集大小基本无关的检索复杂度,这一点对于海量内容的检索来说至关重要。
索引项的通用结构是次关键码、记录号表。其中记录号表具有相同次关键字的所有记录的记录号(可以是指向记录的指针或者是该记录的主关键字)。这样的索引方法就是倒排索引(inverted index)。
#include<iostream>
#include<fstream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
map<string,vector<int> > indextable;//倒排索引表
void init() //初始化表
{
indextable.clear();
}
int main()
{
//重定向从index.txt中读入,输出到result.txt,index.txt,result.txt都是在当前目录下
freopen("index.txt","r",stdin);
freopen("result.txt","w",stdout);
init();
int id; //文件名
string filepath; //文件路径名
while(cin>>id>>filepath)//从index中读入文件名和文件路径名
{
ifstream fin(filepath.c_str());//打开文件路径下的文件,参数应是c风格的字符串
string s;
while(fin>>s)//一个单词一个单词地读入
{
indextable[s].push_back(id);//把当前单词对应的文件名加入到单词对应的ID数组中
}
}
map<string,vector<int> >::iterator map_it;//索引表迭代器
map_it=indextable.begin();
while(map_it!=indextable.end())//遍历整个索引表输出,因为MAP的键值是严格弱排序,因此输出是字典序
{
string tmp=map_it->first;
cout<<tmp<<" ";
for(int i=0;i!=indextable[tmp].size();i++)
cout<<indextable[tmp][i]<<" ";
cout<<endl;
map_it++;
}
return 0;
}