这几天刚刚用C写了一个关于倒排表搜索词条的程序,程序的效果还是可以,但是当词条数量增加后,算法的效率会大大降低。
这里将对算法进行简述,并总结得失。
一, 数据结构
将有两个文件作为索引的可持久化被保存。第一个我称为dictionary,第二个被称为data。
dictionary用来存储索引,其中索引是有序的。其中的每条索引数据包含代表该索引的一个HASH值,索引在data文件中第一次出现的位置FIRPOS和最后一次出现的位置LASTPOS
data用来存储所有出现过的词条,按照词条出现的顺序进行排列,每条数据记录该词条出现的位置和与该词条有同样HASH值的下一个词条位置。
二, 算法流程
- 初始化data和dic两个容器,用于在内存里存放data和dictionary两个文件,并建立对应的结构体——在面向对象语言中可以定义为类
- 读入要建立索引的数据(这里常常需要一个运行良好的分词器,推荐Python的Jieba分词,对中文分词的支持很好,其他语言可以通过运行一个python脚本来生成一个分词结果,然后再读入),加入data容器中
- 计算索引hash值,查找其在dic容器里的位置(可以假定dic容器里数据是有序的,因为我们在算法步骤中会维护其有序性),然后维护dictionary中的最后位置LASTPOS。(维护过程详见伪代码)最后回到第二步,重复,直到没有可以读入的数据为止,索引建立成功。
伪代码如下:
while (!eof)
{
tempData = ReadData;
Data = Divice(tempData);
loop:
hash(Data[i].value);
pos = find(Data[i].value) in dic.LASTPOS;
if pos == -1
new dic for Data[i].value;
else
/*以下就是维护的过程*/
dic[pos].next = i;
dic.LASTPOS = i;
sort(dic);
//结束维护
endloop;
}
三, 总结得失
这个算法总的来说在数据索引较小的时候,因为dictionary有序,find过程可以用二分查找来优化,然而这也引入了一个不好的地方——在索引数非常多的时候,每一步都排序的复杂度会非常大。
即使有人推荐我用希尔排序,效果也并不是很好。所以我想到了对于dic容器,不用队列,而使用树结构,可以方便的做到查找和搜寻。可以尝试采用二叉搜索或者效率更高的红黑树(因为某些索引或许特别的长,这时候采用红黑树来降低树的高度很有必要)、
目前我还没有尝试过用树来优化。其实是因为我项目的问题,即使用二叉搜索树来做也很难让索引和一个int范围内的值产生一一对应。
这也将是我下一步将解决的问题。