Hashes
問題:你有一個很大的字符串數組。須要知道另一個字符串是否在這個字符串數組中。你可能會將這個字符串與數組中的字符串依次做比較。可是實際中,你會發現這種方法太慢。必須找其它的方法。可是除了依次比較字符串外,還有沒有其它方法來知道某個字符串是否存在呢?
解決方案: Hashes。 Hashes是用小的數據類型(如,數字)來表示其它大的數據類型(一般是字符串)。在這種情形下,你可能將字符串存儲在hash數組中。而後你能夠計算要查找字符串的hash值,用這個hash值與數組中的hash值進行比較。若是在hash數組中有一個hash值與這個新的要查詢的hash值相等,則證明這個字符串存在。這個方法, 稱爲索引(indexing)。
本文采用分離連接hash算法來實現基於字符串的hash算法,而且能夠統計某個字符串出現的次數node
#include <stdio.h> #include <stdlib.h> #include <string.h> /*定義hash節點*/ struct hash_node { char *value; /*字符串數據,動態分配內存*/ int count; /*此字符串出現的次數*/ struct hash_node * next; /*解決衝突的分離連接法的next節點*/ }; /*定義hash表結構 * *兩種方式: * * 1. 用數組定義 * * 2. 用鏈表*/ /*用數組*/ #define MAX_HASH_TABLE 10000 /*用鏈表表示*/ struct hash_table { int num; /*記錄hash表的大小*/ struct hash_node **hashlist; /*用指針動態分配hash數組內存大小*/ }; typedef struct hash_node * hash_list; typedef struct hash_table* Hash_Table; /*根據hash表大小,初始化hash表*/ Hash_Table init_hash_table(int hash_size) { Hash_Table hashtable; int i; hashtable = (Hash_Table)malloc(sizeof(struct hash_table)); if(hashtable == NULL) { printf("malloc hashtable error\n"); return NULL; } hashtable->num = hash_size;/*hash數組大小*/ /*爲hash數組動態分配內存*/ hashtable->hashlist = (struct hash_node **)malloc(sizeof(struct hash_node*) * hash_size); if(hashtable->hashlist == NULL) { printf("malloc hashlist error\n"); free(hashtable); hashtable = NULL; return NULL; } /*根據hash數組的大小,爲每個成員分配內存,而且初始化內存*/ for(i = 0; i < hash_size; i++) { hashtable->hashlist[i] = (struct hash_node*)malloc(sizeof(struct hash_node)); if(hashtable->hashlist[i] == NULL) { printf("malloc hashtable->hashlist error\n"); exit(1); }else { hashtable->hashlist[i]->value = NULL; hashtable->hashlist[i]->count= 0; hashtable->hashlist[i]->next = NULL; } } return hashtable; } /*獲取hash key值的hash算法函數*/ unsigned long get_hash_index(const char *key,int hash_size) { unsigned long ulHash = 0; while(*key) { ulHash += (ulHash << 5) + *key++; } return (ulHash % hash_size); } /*在hash表中插入一個字符串*/ int hash_insert(char *string, Hash_Table hash_table) { unsigned long index; hash_list hash; index = get_hash_index(string,hash_table->num); hash = hash_table->hashlist[index]; if(hash == NULL) { hash = (hash_list)malloc(sizeof(struct hash_node)); if(hash == NULL) { printf("error: malloc hashlist failed\n"); return -1; }else { memset(hash,0,sizeof(struct hash_node)); hash->value = (char*)malloc(strlen(string)+1); hash->count++; strncpy(hash->value,string,strlen(string)+1); } }else { while(hash) { if(hash->value != NULL) { if(strcmp(hash->value,string) == 0) { hash->count++; return 0; } hash=hash->next; }else { hash->value = (char*)malloc(strlen(string)+1); hash->count++; strncpy(hash->value,string,strlen(string)+1); return 0; } } } return 0; } hash_list hash_find(const char *string, Hash_Table hash_table) { unsigned long index; hash_list hash; index = get_hash_index(string,hash_table->num); hash = hash_table->hashlist[index]; while(hash) { if((hash->value != NULL) && (strcmp(hash->value,string) == 0)) { printf("find %s in hash table.....\n",string); return hash; } hash = hash->next; } return NULL; } int main(int argc, char *argv[]) { Hash_Table hash_table; int rc = 0; hash_list hash; hash_table = init_hash_table(MAX_HASH_TABLE); //rc = hash_insert("wgw",hash_table); rc = hash_insert("cdef",hash_table); rc = hash_insert("abcd",hash_table); rc = hash_insert("cdef",hash_table); hash = hash_find("cdef",hash_table); if(hash) { printf("hit num of cdef is %d\n",hash->count); } hash = hash_find("wgw",hash_table); printf("%s\n",hash?"find wgw":"can't find wgw"); if(hash) printf("num=%d\n",hash->count); }
運行結果:
面試
海量數據面試題:
搜索引擎會經過日誌文件把用戶每次檢索使用的全部檢索串都記錄下來,每一個查詢串的長度爲1-255字節。
假設目前有一千萬個記錄(這些查詢串的重複度比較高,雖然總數是1千萬,但若是除去重複後,不超過3百萬個。一個查詢串的重複度越高,說明查詢它的用戶越多,也就是越熱門。),請你統計最熱門的10個查詢串,要求使用的內存不能超過1G。算法
分析:
不超過3百萬個,假設都是最大的255個字節,加上next指針和技術count總共255+4+4=263bytes
3000000*263=789000000~~~~789Mbytes小於1G內存。並且這個是考慮到極限狀況,通常不會因此都是255字節。
能夠考慮用上面的hash算法,來統計次數,而後用排序算法獲取最大的10個查詢串。數組