我有一项任务要完成。它说我必须阅读一个包含3百万字符串的文件 我必须读取文件并构建一个结构来保存字符串。该系统必须能够回答“这个新字符串是否存在?”的问题。
我还希望将列表分解为字符串的“桶”,以便'匹配的字符串'能够选择正确的桶来搜索(快速),并且该桶应该包含不超过总数/ hashMask字符串左右(即每桶3,000,000 / 0xFFF == 732个对象)。
现在我已经创建了一个哈希表,列表和函数的结构来读取文件,添加和删除功能。但我对粗体输入的文字一无所知。我是否需要在Hash函数中提取某些内容(以粗体显示)?
以下是我的示例代码
#define MAX_NAME 100
/* Linked list structure */
typedef struct list
{
char *string;
int index;
struct list *next
} list_t ;
/* hash table structure*/
typedef struct hashTable
{
int size; // size of the table
list_t **table; // the table element
} hash_table_t;
HashListType *createHashTable( size_t size)
{
// allocate hash table ..I know how to do it
}
unsigned int hash(HashListType *hashTable, void *str )
{
uint64_t hashVal;
hashVal = 0;
while( *str != '\0')
{
hashVal = *str + (hashVal << 5 ) - hashVal;
str++;
}
return (hashVal % hashTable->size);
}
void addToHashList( HashListType *list, void *obj, uint64_t hash)
{
// add item of new list to table --> have an idea how to do it
}
void removeFromHashList(HashListType *list, void *criterion, uint64_t hash )
{
// got an idea how to do it
}
/*
this function will read the file (assume one string per line)
and create the list of lists (list of buckets), adding one object per string.
*/
HashList *loadDataSet(char *filename, int hashMask)
{
// to read a file
char readString[ MAX_NAME];
File *fp ;
if( (fp = fopen(filename, "r") )== NULL)
{
printf(" failed to open the file\n");
exit(0);
}
while( fgets ( readString,MAX_NAME -1, fp ) != NULL)
{
//need to break the list down into "buckets" of strings so the 'string to match'
// is able to chose the correct bucket to search in (quickly)
//and that bucket should contain no more than total/hashMask strings
or so (ie 3,000,000 / 0xFFF == 732 objects per bucket).
}
fclose(fp);
}
答案 0 :(得分:2)
我相信您为哈希表选择了错误的数据结构:
typedef struct hashTable
{
char key[MAX_NAME];
int index;
struct hashTable *next;
struct hashTable *prev;
};
哈希表的一个主要好处是能够直接跳转到包含您要搜索的元素的存储桶。这是散列桶的链接列表的一部分 - 这意味着您必须在每次查找或插入上迭代平均4098/2个桶。这不会为您提供所需的性能。
您的哈希表应该是structs
的数组;每个struct
应该有一个指向字符串的指针(或短字符串的直接存储)和指向存储桶中下一个struct
的指针。 (虽然此struct hashTable
也是存储桶内结构,但它是一个罕见的哈希表,需要在存储桶中使用next
和prev
个链接。为什么我猜这个数据结构是用于表本身。)
您还需要选择一个好的hash function。有很多关于良好哈希函数的研究,但你真的在寻找一些比做作业更好的东西。散列函数的输入是您的字符串,输出应该是整数。你需要%
输出你的数组大小(选择接近5000的素数)来确定要使用哪个存储桶。
这是stb.h
library of convenient functions:
unsigned int stb_hash(char *str)
{
unsigned int hash = 0;
while (*str)
hash = (hash << 7) + (hash >> 25) + *str++;
return hash + (hash >> 16);
}
一个简短的暗示,虽然stb.h
代码属于公共领域,但在程序中引用来源是非常明智的 - 教授,律师以及将来的同事,谢谢你包括你自己没做过的事情的来源。
答案 1 :(得分:1)
哈希函数不仅可以定义为整数,还可以定义为字符或字符串(提示:字符编码)。 为字符串创建哈希函数。 提交时,必须与输出文件一起提交或运行。
答案 2 :(得分:0)
注意:这个答案取决于你的任务文本使用“桶”的严格程度,因为我解释你的问题比你的示例代码更宽松。
此任务的无疑最佳数据结构是Trie或其概括。您可以构建一个树,其中每个节点包含存储字符串的一个 atom 的“微小”哈希表。例如,字符串的原子可以是单个字符。您可以参数化您的数据结构以更改原子的大小(即每个节点具有16个子尝试的固定数组,因此您的原子长度为4位) - 此阵列方法允许恒定时间下降但需要相对较小很大的记忆力。但正如我所说,你可以使用微小的哈希表(与你的任务更兼容)而不是快速查找数组。