問題の場合、64ビットマシン上のポインタはデータの長さとほぼ一致します。したがって、問題で文字列ごとに複数のポインタを使用すると(平均長が10バイト未満)、データ構造のサイズが入力のサイズを支配することになります。
これに対処する一般的な方法の1つは、文字列を表すためにポインタを使用しないことです。すべての文字列が格納される大きなページへの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);
}
};
ここfind_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;
}