倒排索引--二叉树

本文介绍了使用二叉树构建倒排索引的过程,针对13M数据,算法在6秒内完成,实现了高效的搜索。算法遍历文件中每个字符,建立二叉树并统计字符出现次数。然后根据次数分配空间,存储字符位置信息。通过内存区查找即可获取字符位置。部分代码展示供交流学习。

这两天写了一个索引的建立与搜索过程,目前是对13M的数据进行了测试,整个过程只用了不到6s,这个数字是值得庆祝的。算是一个比较快的算法了。在此要感谢wang sir和xu sir的支持。对这两位表示由衷的感谢。

整个算法过程对文件中每个字符进行了一次遍历,对每次得到的字符进行建立二叉树(综合考虑,二叉树还是最好的一个数据结构),并且统计总共有多少个字符和每个字符出现的次数,存放在一个数组中,还对每次出现的不重复字符进行编号(一个字对于一个号,该号是从小往大排的)。这是第一步的遍历:建立二叉树。

在第一步结束后就得到了两个变量,一个存放出现次数的数组,另一个是总共有多少字符。有了出现次数,就可以计算出将来存放每个字符所用的空间大小(出现一次就申请一个int的大小共32位,这时候前24位存放所在行号,后8位存放对于行首的偏移量),有了需要空间大小就可以申请一段连续的内存,专门存放每个字符的所在位置。对这片连续内存的存放算法是:根据每个字的编号和第一步统计的数组能得到对于编号相对于首地址的偏移量,把该字的位置连续写到首地址+偏移量所指向的内存区。一个字出现多次,就按照出现的顺序依次写入。最终我们只需要对这片内存区进行查找就能得到所检索字的位置(行号和偏移号)。由于有点牵涉到公司机密问题,我只是把部分代码粘出来,以供大家批评、指正、交流、学习。有问题可以私信。。。。。

看代码:

这是程序需要的数据结构

typedef struct node {
	char str[3];//对应字符串
	int line_num;//对应行号
	int n;//对应的N值
	int off_n;//对应偏移量
	int appear;
	struct node *left,*right;
}Bnode;
FILE *stream;
int line=1;//记录行号
int str_appear_num[6000];//每个字符串出现的次数
int str_apppear_n=0;//文件中字符数
int str_n = 0;//每个字符串对应的n值
int off_num = 1;//对应字符串的偏移量
int sum[6000];//每个编号前出现字符量

unsigned int *p_map;//终极boss
//创建二叉树
Bnode *create_tree(Bnode *p,char *string){
	
	if(p != NULL){
		if(strcmp(p->str,string) > 0)
			p->left = create_tree(p->left,string);
		else if(strcmp(p->str,string) <0)
			p->right = create_tree(p->right,string);
		else{
			str_appear_num[p->n]++;//相同自加1
		}
	}
	else{
		p = (Bnode *)malloc(sizeof(Bnode));
		if(p == NULL) return p;
		p->n = str_n++;
		p->off_n = off_num++;
		str_apppear_n++;
		p->line_num = line;
		p->appear=0;
		strcpy(p->str,string);
		p->left = NULL;
		p->right = NULL;
		//printf("%s",p->str);
	}
	return p;
}

//第二次遍历,往内存中写字符位置
void fuc(Bnode *p,char *string){
	if(p != NULL){
		//str_n++;
		//off_num++;
		if(strcmp(p->str,string) > 0)
			fuc(p->left,string);
		else if(strcmp(p->str,string) <0)
			fuc(p->right,string);
		else{
			*(p_map+sum[p->n]+(p->appear)) = ((0xffffff & (line))<<8)|(off_num & 0xff);
			p->appear++;//相同自加1	
			return ;
		}
	}
	
}

检索:先找到字符对应的编号。然后根据各种偏移找到该字符的位置

int find_N(Bnode *p,char *string){
	if(p != NULL){
		if(strcmp(p->str,string) > 0)
			find_N(p->left,string);
		else if(strcmp(p->str,string) <0)
			find_N(p->right,string);
		else{		
			return p->n;
		}
	}
	else return -1;
}
//打印出检索到字的行号和偏移量
void print_result(int k,int n){
	int i;
	unsigned int *p_map_temp=p_map;
	for(i=0;i<k;i++){
		//printf("the first is %x \n",*(p_map_temp+sum(n)+i));
		printf("%d line,%d off\n",((*(p_map_temp+sum[n]+i))&0xffffff00)>>8,(*(p_map_temp+sum[n]+i))&0xff);
	}
}

void find_str(Bnode *p,char *string){
	int i,k;
	
	int n = 0;
	n = find_N(p,string);
	if(n == -1){
		printf("No result!\n");
		return ;
	}
	k=str_appear_num[n];
	printf("find the string num is %d n=%d \n",k,n);
	//print_result(k,n);
}

主函数:

main(){

................

}
有图为证:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值