【问题标题】:Two-way hash table双向哈希表
【发布时间】:2017-03-27 03:42:33
【问题描述】:

对于某些编译语言,是否有高效的哈希表实现,它将键(整数)映射到值(字符串),反之亦然?

当然,一个表总是可以有两个表,一个用于 key=>value 映射,另一个用于 value=>key。但是,这不会非常有效,至少在内存方面不是。如果类型系统和预期用途允许,两个映射可能都在一个表中。

【问题讨论】:

  • 实现起来并不难。只需使用有效负载+(2 组 {head,next} 指针)创建条目,外加一些处理它的机制。
  • 对,这似乎比使用两个哈希表更节省内存。另一方面,在实现表的重新分配时,指针可能会让人头疼。
  • 固定尺寸​​与可变尺寸可以作为设计选择。 OTOH 调整大小/加倍并不难(如果您不使用存储的指针,则相对容易)
  • 但是在你的方法中你会的,不是吗?
  • 不,在这种情况下,我更喜欢为 {head,next} 存储索引),因为这些在 resize/realloc() 之后是稳定的

标签: data-structures hash hashmap hashtable


【解决方案1】:

它的一个名称是 BiMap(如双向)。明显的限制是键是不同的(就像在普通字典/地图中一样),但值也是如此。

对于 Java,有一个 StackOverflow question on it,但一般建议是 Guava BiMap

对于 C 和 C++,Boost has a Bimap

在内部,这是您提到的“低效”实现,它保留了两个哈希表。事情是这样的:它高效的,并且预期使用两倍的内存用于二级查找结构,而且很少有什么大不了的。

【讨论】:

  • 你怎么知道它在内部保存了两个哈希表?你说的“它”是什么意思?对于Java,“这两个 bimap 由相同的数据支持”,我认为没有重复。 Boost.Bimap doc 说“Boost.MultiIndex 实际上是 bimap 容器的核心”,在我看来,只有一组具有两个索引的数据。
  • 对于 Guava,这是他们的HashBiMap implementation。请注意两个内部哈希表。 “相同数据”的意思是存储在这两个映射中的引用是相同的,所以 data 实际上并没有被复制,只是引用。
【解决方案2】:

这是我用于 bihash 的数据结构: 每个条目的开销是四个整数(用于索引)。

在下面的示例中,使用 typedef unsigned char Index; 时,开销将是四个字符,最大表容量为 255。


        /* For demonstration purposes these types are VERY SMALL.
        ** Normally one would use unsigned short, or unsigned int.
        */
typedef unsigned char Index;
typedef unsigned short Hashval;
        /* Use the maximal representable value as sentinel value */
#define NIL ((Index)-1)

struct entry {
        Index head_key          /* The head-of-the-chain pointers */
                , head_val;     /* ... and for the values */
        Index next_key          /* linked list for chaining the keys */
                , next_val;     /* ... and for the values */
        };

struct table {
        unsigned totlen, keylen;
                /* free points to the root of the freetree */
        Index size, free;
                /* The complete payload, for both keys and values.
                 * layout = [key0|val0|key1|val1|..] (without padding/alignment)
                 */
        char *data;
        struct entry *entries; /* All the entries. Not pointers, but the actual entries. */
        };
        /* Macros for accessing the pool of payload */
#define NODE_KEY(p,n) ((p)->data + (n) * (p)->totlen)
#define NODE_VAL(p,n) ((p)->data + (n) * ((p)->totlen+(p)->keylen))

#define TH_OK 0
#define TH_KEY_NOT_FOUND 1
#define TH_VAL_NOT_FOUND 2
#define TH_BOTH_NOT_FOUND 3
#define TH_TABLE_FULL 4
#define TH_KEY_DUPLICATE 5
#define TH_VAL_DUPLICATE 6
#define TH_BOTH_DUPLICATE 7
#define TH_TOTAL_ECLIPSE 8

/********************************************/

    /* Allocate and initialise the hash table.
    ** Note: given fixed size, the table and the payload could be statically allocated,
    ** (but we'd still need to do the initialisation)
    */


struct table * table_new( unsigned keylen, unsigned vallen, unsigned totcount )
{
Index idx;
struct table *this;

if (totcount > NIL) {
        fprintf(stderr, "Table_new(%zu,%zu,%zu): totcount(%zu) larger than largest Index(%zu)\n"
                , (size_t) keylen, (size_t) vallen, (size_t) totcount
                , (size_t) totcount, ((size_t)NIL) -1 );
        return NULL;
        }
this = malloc (sizeof *this);
this->size = totcount;
this->keylen = keylen;
this->totlen = keylen+vallen;
this->data = malloc (totcount * this->totlen );
this->entries = malloc (totcount * sizeof *this->entries );

this->free = 0; /* start of freelist */
for( idx=0; idx < this->size; idx++ ) {
        this->entries[idx].head_key = NIL;
        this->entries[idx].head_val = NIL;
        this->entries[idx].next_key = NIL;
        this->entries[idx].next_val = idx+1; /* unused next pointer reused as freelist */
        };
this-> entries[idx-1].next_val = NIL; /* end of freelist */

fprintf(stderr, "Table_new(%zu,%zu,%zu) size = %zu+%zu+%zu\n"
                , (size_t) keylen, (size_t) vallen, (size_t) totcount
        , sizeof *this, (size_t)totcount * this->totlen, totcount * sizeof *this->entries
         );

return this;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    • 2011-03-20
    相关资源
    最近更新 更多