1. 程式人生 > >搜尋引擎中快取(cache)用到的雜湊(hash)演算法

搜尋引擎中快取(cache)用到的雜湊(hash)演算法

前一段查看了關於雜湊的各種演算法,發現流傳最廣的還算偉大的暴雪(dota愛好者)工程師得到的一種演算法,有很多部落格中都有對其的介紹,我在此就不多廢話了。

雖說是借鑑,也只是一小部分的抄襲。不知道是否冒犯了暴雪的版權。

我修改成了我需要的功能,我的目標是對6w資料進行雜湊計算然後暫存到記憶體中,當做快取使用。這是搜尋引擎中必須要做的一步,當然,程式碼是公司機密,我只是把我寫的程式碼雛形拿出來,看看有沒有值得批評指正的地方。

小弟不才,在這6w的測試資料中,使用5倍的記憶體,得到最長的一串連結串列長達180.(不知道大家知道不知道我說的是什麼意思)。溝通的機會來了。。。。。

歡迎到之類來溝通交流:

還是看看程式碼:

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

//#define DEBUG	
#define NUM 10240	//快取的最大資料量
typedef struct hash{
	char flag;
	char hz[64];
	char *art;
	int time;
	int n;
	struct hash *next;
}HASH;
HASH *hashtable1=NULL,*hashtable2=NULL,*hashtable3=NULL,*hashtable4=NULL,*hashtable5=NULL;
unsigned long cryptTable[0x500]; 

/******************************************************
*	函式功能:申請雜湊表所用的記憶體;
*	函式引數:void;
*	函式輸出:成功:1;失敗:-1;
******************************************************/
int getMalloc(){
	hashtable1 = (HASH *)malloc((NUM)*sizeof(HASH));
	hashtable2 = (HASH *)malloc(NUM*sizeof(HASH));
	hashtable3 = (HASH *)malloc(NUM*sizeof(HASH));
	hashtable4 = (HASH *)malloc(NUM*sizeof(HASH));
	hashtable5 = (HASH *)malloc(NUM*sizeof(HASH));
	memset(hashtable1,0,(NUM)*sizeof(HASH));
	memset(hashtable2,0,NUM*sizeof(HASH));
	memset(hashtable3,0,NUM*sizeof(HASH));
	memset(hashtable4,0,NUM*sizeof(HASH));
	memset(hashtable5,0,NUM*sizeof(HASH));
	if(hashtable1==NULL||hashtable2==NULL||hashtable3==NULL||hashtable4==NULL||hashtable5==NULL)
	{
		perror("get Malloc error");
		return -1;
	}
	return 1;
}

/******************************************************
*	函式功能:生成一個長度為0x500的cryptTable[0x500];
*	函式引數:void;
*	函式輸出:void;
******************************************************/ 
void prepareCryptTable()  
{   
    unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;  
  
    for( index1 = 0; index1 < 0x100; index1++ )  
    {   
        for( index2 = index1, i = 0; i < 5; i++, index2 += 0x100 )  
        {   
            unsigned long temp1, temp2;  
  
            seed = (seed * 125 + 3) % 0x2AAAAB;  
            temp1 = (seed & 0xFFFF) << 0x10;  
  
            seed = (seed * 125 + 3) % 0x2AAAAB;  
            temp2 = (seed & 0xFFFF);  
  
            cryptTable[index2] = ( temp1 | temp2 );   
       }   
   }   
} 

/******************************************************
*	函式功能:	計算lpszFileName 字串的hash值;
*	函式引數:	字串指標 、運算型別(可以去0、1、2);
*	函式輸出:	雜湊值;
******************************************************/ 
unsigned long HashString( char *lpszFileName, unsigned long dwHashType )  
{   
    unsigned char *key  = (unsigned char *)lpszFileName;  
	unsigned long seed1 = 0x7FED7FED;  
	unsigned long seed2 = 0xEEEEEEEE;  
    int ch;  
	
    while( *key != 0 )  
    {   
        ch = toupper(*key++);  
  
        seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);  
        seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;   
    }  
    return ((seed1*2654435769)%NUM);//seed1%5000   
}  

/******************************************************
*	函式功能:	往雜湊表中對應節點的記憶體中寫內容
*	函式引數:	ptr:雜湊表中一個節點指標 str:關鍵詞
*	函式輸出:	void
******************************************************/ 
void writemem(HASH *ptr,char *str){
	#ifdef DEBUG
	static int i=0;
	i++;
	printf("i=%d\n",i);
	#endif
	#ifdef DEBUG
	printf("-------writemem start--------\n");
	#endif
	HASH *p=ptr,*q;

	while(p->next != NULL){
		p=p->next;
	}
	#ifdef DEBUG
	printf("----sizeof(HASH):%d-----\n",sizeof(HASH));
	#endif
	HASH *p_hash=NULL;
	p_hash = (HASH *)malloc(sizeof(HASH));
	memset(p_hash,0,sizeof(HASH));
	#ifdef DEBUG
	printf("----------1------------\n");
	#endif
	if(p_hash == NULL){
		perror("p_hash malloc error");
	}
	strcpy(p_hash->hz,str);
	p_hash->flag = 1;
	p_hash->next=NULL;
	/*此處還需加上拷貝搜尋內容的程式碼*/
	p->next=p_hash;
	#ifdef DEBUG
	printf("-------writemem end--------\n");
	#endif
}

/******************************************************
*	函式功能:	往雜湊表中寫資料
*	函式引數:	n:雜湊值 hz:關鍵字數 str:關鍵字
*	函式輸出:	void
******************************************************/ 
void writeHash(int n,int hz,char *str){
	#ifdef DEBUG
	printf("-------writeHash start--------\n");
	#endif
	switch(hz){
		case 1:
		writemem((hashtable1+n),str);
		break;
		case 2:
		writemem((hashtable2+n),str);
		break;
		case 3:
		writemem((hashtable3+n),str);
		break;
		case 4:
		writemem((hashtable4+n),str);
		break;
		case 5:
		writemem((hashtable5+n),str);
		break;
		case 6:
		case 7:
		case 8:
		case 9:
		break;
		default:
		break;
	}
	#ifdef DEBUG
	printf("-------writeHash end--------\n");
	#endif
}

/******************************************************
*	函式功能:	遍歷雜湊表,查詢有多少內容
*	函式引數:	void
*	函式輸出:	void
******************************************************/ 
void countHash(){
	int i;
	int all=0;
	for(i=0;i<NUM;i++){
		HASH *p=hashtable1+i;
		while(p->next!=NULL){
			p=p->next;
			all++;
		}
		p=hashtable2+i;
		while(p->next!=NULL){
			p=p->next;
			all++;
		}
		p=hashtable3+i;
		while(p->next!=NULL){
			p=p->next;
			all++;
		}
		p=hashtable4+i;
		while(p->next!=NULL){
			p=p->next;
			all++;
		}
		p=hashtable5+i;
		while(p->next!=NULL){
			p=p->next;
			all++;
		}
	}
	printf("the title = %d\n",all);
}

/******************************************************
*	函式功能:	刪除雜湊表中某一個節點上的內容
*	函式引數:	ptr:雜湊節點指標 str:關鍵字
*	函式輸出:	找到刪除的節點並正確刪除返回1;否則返回0
******************************************************/ 
char deletemem(HASH *ptr,char *str){
	HASH *p=ptr,*q;
	while(p!=NULL){
		if(strcmp(p->hz,str) == 0){
			q->next=p->next;
			/*此處還需加上釋放存放搜尋結果記憶體的程式碼*/
			free(p);
			return 1;
		}
		q=p;
		p=p->next;
	}
	printf("delet fail\n");
	return 0;
}

/******************************************************
*	函式功能:	往雜湊節點
*	函式引數:	n:雜湊值 hz:關鍵字數 str:關鍵字
*	函式輸出:	void
******************************************************/ 
void deleteNode(int n,int hz,char *str){
	#ifdef DEBUG
	printf("-------delete start--------\n");
	#endif
	switch(hz){
		case 1:
		deletemem((hashtable1+n),str);
		break;
		case 2:
		deletemem((hashtable2+n),str);
		break;
		case 3:
		deletemem((hashtable3+n),str);
		break;
		case 4:
		deletemem((hashtable4+n),str);
		break;
		case 5:
		deletemem((hashtable5+n),str);
		break;
		case 6:
		case 7:
		case 8:
		case 9:
		break;
		default:
		break;
	}
	#ifdef DEBUG
	printf("-------delete end--------\n");
	#endif
}

int main(){
	int error=0;
	int flag=1,count=0;
	unsigned long ulHashValue;
	char *hzString=(char *)malloc(256);
	if(hzString==NULL){
		perror("hzString malloc error");
	}
	error = getMalloc();
	if(error==-1){
		perror("malloc hash error");
		//暫時不做處理
	}
	FILE *stream,*fdata;
	fdata=fopen("data.txt","w+");
	stream=fopen("test.txt","r+");
	srand((int)time(NULL));
	while(1){
		int hz=0;
		while(hz == 0)
			hz=((unsigned int)rand())%5;
		char ch[4];
		int i;
		for(i=0;i<hz;i++){
			memset(ch,0,sizeof(ch));
			ch[0] = fgetc(stream);
			if(ch[0]==EOF){
				flag=0;
				break;
			}
			if(ch[0] < 0){
				ch[1] = fgetc(stream);
				if(ch[1] == EOF){
					flag=0;
					break;
				}
			}
			strcat(hzString,ch);
		}
		count++;
		if(flag==0||count>NUM)
			break;
		prepareCryptTable();
		ulHashValue = HashString(hzString,0);
		char p[20];
		memset(p,0,20);
		sprintf(p,"%u\n",(unsigned int)ulHashValue);
		fwrite(p,1,strlen(p),fdata);
		#ifdef DEBUG
		printf("ulHashValue=%u\n",(unsigned int)ulHashValue);
		#endif
		writeHash(ulHashValue,hz,hzString);
		if(count%5==0){
			deleteNode(ulHashValue,hz,hzString);
		}
		memset(hzString,0,256);
	}
	#ifdef DEBUG
	#endif
	countHash();
	
	free(hzString);
	fclose(fdata);
	fclose(stream);
	return 0;
}