2013-05-22 20 views
0

我必须设计和实现数据结构,其类似于bimap,bidimapdualmap,即散列表,其中值可以用于提取键,当然也可以用于反方向。具有特定要求的纯C通用双向哈希表

通常情况下,它可以在两个独立的散列表的顶部来实现,但也有一些具体的要求:运行期间

  1. 的内存分配(更好地分配所有的内存在启动时只)
  2. 份额在启动时
  3. 相同的数据(如果实现为两个哈希表)
  4. 上限已知
  5. 键和值可以是任何数据结构(通用)的项的数目,但长度是固定的
  6. 只有C,没有STL,从头
  7. 支持删除操作

我至今是:

typedef struct HashTable { 
    int key_len; 
    int data_len; 
    int num_buckets; 
    HashEntry *buckets; 
} HashTable; 

typedef struct HashEntry { 
    void* key; 
    void* data; 
    HashEntry* next; //list for collision resolution 
} HashEntry; 

HashTable* createHashTable (int max_capacity, int num_buckets, int key_len, int data_len); 

所以该计划是创建两个哈希表,每个桶的数组。

在长度max_capacity/num_buckets

然后分配字节数组来共享数据,并作为存储器池的条目,每个条目桶预分配列表:

char* p = malloc((key_len+data_len) * max_capacity);

然后放函数会把键和数据放到字节数组中,两个哈希表都会相应地分配keydata指针。来自

  1. 碰撞

    的主要挑战(超过水桶预期数量,这将需要额外拨款)的内存池的

  2. 删除操作和管理

如何你会改进设计来应对这些挑战吗?

+0

你能确保*键*和键值都是唯一的(并且映射是双射),或者几个键指向相同的值,或者一个键指向多个值(但是*键,值}仍然是唯一的)?在这两种情况下:当检测到重复时,你想要发生什么? – wildplasser

+0

@wildplasser,键和值是唯一的。 –

+0

顺便说一句:你需要'buckets'数组的两个版本,以及'HashRntries'中的两个' - > next'指针;键和值都需要它们自己的表头和表链。 2)如果键和数据的大小是固定的,你可以将它们存储在一个大数组中(如问题中的'* p'数组),甚至可以存放在HashEntries中。这里不需要指针。 3)下一个指针相同;既然你知道大小是固定的,你可以使用索引而不是指针。索引将受到表大小的限制,可能是16甚至8位宽。 – wildplasser

回答

0

冲突解决

我不认为碰撞真的要需要额外的分配操作,如果你正确设置它。分配您将能够使用的最大RAM。用一些标志位设置您的存储桶来进行会计核算。你可以借用inode使用的方案;作为一个女儿,你有一个新的未使用的桶链接,你有很大的散列冲突。

考虑

如果不知何故你的钥匙是这样的,您的数据得到了很多的散列碰撞或者你的发行是片面的,因为几个按键习惯了很多,你最终可能有碎片整理您的一路上的桌子。但这只是重写数据的时间间隔比使用该设备的间隔长得多。

删除内存管理。

您将不得不做指针和边界会计,但这就是它。这不是一个新问题。文件系统一直这样做。

+0

你能提出更多关于内存管理的建议吗?如果我需要删除一些条目,这意味着预分配的内存中的某些块可以重用。所以我需要跟踪这一点。我已经阅读了关于自由列表,这对于固定大小的块很有用。但是列表本身需要动态内存。 –

+0

@NikolayKuznetsov:由于你的大小和元素的数量是固定的,你可以预先分配一个(count *(keysize + valueside))大块内存,并把你的负载放在那里。不需要freelists,每个节点都拥有它自己的子块。 – wildplasser