对于您的问题,64 位机器上的指针几乎与您的数据长度匹配。因此,在您的问题中使用每个字符串的多个指针(平均长度小于 10 个字节)将使数据结构的大小支配您的输入大小。
处理该问题的一种通用方法是不使用指针来表示您的字符串。使用 32 位偏移量到存储所有字符串的大页面中的专门表示将使您的指针内存需求减半,但代价是需要对指针进行添加以检索您的字符串。
编辑:下面是这种表示的示例(未经测试)实现(struct
为了简单起见,实际实现当然只会公开用户界面)。该表示假设一个哈希表插入,因此为next_
. 请注意,偏移量按大小缩放,hash_node
以允许以 32 位偏移量表示。
struct hash_node {
uint32_t next_;
char * str () { return (const char *)(&next+1); }
const char * str () const { return (const char *)(&next+1); }
};
struct hash_node_store {
std::vector<hash_node> page_; /* holds the allocated memory for nodes */
uint32_t free_;
hash_node * ptr (uint32_t offset) {
if (offset == 0) return 0;
return &page_[offset-1];
}
uint32_t allocate (const char *str) {
hash_node *hn = ptr(free_);
uint32_t len = strlen(str) + 1;
uint32_t node_size =
1 + (len / sizeof(hash_node)) + !!(len % sizeof(hash_node));
strcpy(hn->str(), str);
free_ += node_size;
return 1 + (hn - &page_[0]);
}
};
哈希表将包含一个节点存储和一个哈希桶向量。
struct hash_table {
hash_node_store store_;
std::vector<uint32_t> table_; /* holds allocated memory for buckets */
uint32_t hash_func (const char *s) { /* ... */ }
uint32_t find_at (uint32_t node_offset, const char *str);
bool insert_at (uint32_t &node_offset, const char *str);
bool insert (const char *str) {
uint32_t bucket = hash_func(s) % table_.size();
return insert_at(table_[bucket], str);
}
bool find (const char *str) {
uint32_t bucket = hash_func(s) % table_.size();
return find_at(table_[bucket], str);
}
};
Wherefind_at
和insert_at
只是以预期方式实现的简单功能。
uint32_t hash_table::find_at (uint32_t node_offset, const char *str) {
hash_node *hn = store_.ptr(node_offset);
while (hn) {
if (strcmp(hn->str(), str) == 0) break;
node_offset = hn->next_;
hn = store_.ptr(node_offset);
}
return node_offset;
}
bool hash_table::insert_at (uint32_t &node_offset, const char *str) {
if (! find_at(node_offset, str)) {
uint32_t new_node = store_.allocate(str);
store_.ptr(new_node)->next_ = node_offset;
node_offset = new_node;
return true;
}
return false;
}