我试图在C ++中实现Extendible Hashing
这是一个充当索引的结构,它包含一个类型数组' Bucket'
Bucket * bucket_pointers;
还有另一个结构,Bucket,它有一个数组,保存我的值
E values[N] = {};
我有一个或多或少的工作程序,有一个问题:每次我将哈希表的大小加倍,我将所有桶都复制到一个新阵列(两倍大小)
Ehqs<i,4,> n = 6, index_size4, global_depth2
Index_0
Bucket <n= 3, local_depth=2, 0x100200000>
[12,4,,8,]
Index_1
Bucket <n= 0, local_depth=1, 0x100200028>
[,,,,]
Index_2
Bucket <n= 3, local_depth=2, 0x100200050>
[2,10,6,,]
Index_3
Bucket <n= 0, local_depth=1, 0x100200078>
[,,,,]
但是,地址为0x100200078的Bucket实际上应指向地址为0x100200028的存储桶,即索引(1和3)应指向同一个存储桶。
我决定是分割一个桶还是加倍索引的大小...
while (!bucket_pointers[h%index_size].append(e)){
if(bucket_pointers[h%index_size].local_depth<global_depth){
split(hashValue);
}
else if(bucket_pointers[h%index_size].local_depth==global_depth){
resize();
}
}
我目前正在将我的阵列的大小加倍:
for (size_t i = 0; i < index_size; ++i){
for (size_t j = 0; j < bucket_pointers[i].n; ++j){
newBucket_pointers[i] = bucket_pointers[i];
newBucket_pointers[i+index_size] = bucket_pointers[i];
}
}
我尝试更改最后一行以接受引用,如下所示:
newBucket_pointers[i+index_size] = &bucket_pointers[i];
然而,这给了我错误&#34;没有可行的超载&#39; =&#39;&#34;, 没有已知的从template :: Bucket *到const template :: Bucket
的转换答案 0 :(得分:2)
请注意,Bucket * bucket_pointers;
不是Bucket指针数组,因为它的名称意味着。它是指向Bucket的指针(Buckets数组中的第一个Bucket是特定的)。
因此,当您将存储区数组复制到另一个存储区时,最终会得到相同的存储区副本,每个存储区都有自己的values
数组。
newBucket_pointers[i] = bucket_pointers[i];
newBucket_pointers[i+index_size] = bucket_pointers[i];
如果您希望newBucket_pointers[i]
和newBucket_pointers[i+index_size]
成为指向同一Bucket
的指针,那么bucket_pointers
(和newBucket_pointers
)的类型实际应该是Bucket**
。然后bucket_pointers
是指向Bucket*
的指针,bucket_pointers[i]
是指向Bucket的指针。这样bucket_pointers[i]
,newBucket_pointers[i]
和newBucket_pointers[i+index_size]
将指向同一个Bucket。我建议使用std::vector<Bucket*> bucket_pointers
,以便更轻松地进行内存管理。
相反,如果您打算像现在一样复制Buckets,但让values
成员指向共享阵列,那么您可以保持bucket_pointers
原样并且需要更改类型values
到指针并分别分配数组。如果你想以这种方式共享数组,你应该使用shared_ptr
来最终解除分配。
答案 1 :(得分:1)
我在下面添加了一些代码,它是一个非常简单的哈希表。它仅用于指导目的,并不足以在实际应用中使用。在现实生活中使用内置的std :: unordered_set可以更好地工作。
通过使用链接列表作为可根据需要扩展的存储桶,我可以避免更改存储桶大小。
此示例是否有助于您设置正确的轨道?
#include <iostream>
#include <array>
#include <list>
#include <string>
#include <cassert>
class CTable
{
public:
void Add(const std::string &sKey, int nVal);
int Find(const std::string &sKey);
protected:
size_t Index(const std::string &sKey);
private:
struct SData
{
SData(const std::string &s, int n)
: sKey(s)
, nVal(n)
{
}
std::string sKey;
int nVal;
};
typedef std::list<SData> Bucket_t;
enum { nBuckets = 24 };
typedef std::array<Bucket_t, nBuckets> Table_t;
Table_t m_table;
const SData *Lookup(const Bucket_t &b, const std::string &sKey);
};
void CTable::Add(const std::string &sKey, int nVal)
{
size_t nIndex = Index(sKey);
const SData *p = Lookup(m_table.at(nIndex), sKey);
if (p)
throw std::runtime_error("duplicate key");
m_table.at(nIndex).push_back(SData(sKey, nVal));
}
int CTable::Find(const std::string &sKey)
{
size_t nIndex = Index(sKey);
const SData *p = Lookup(m_table.at(nIndex), sKey);
if (p)
return p->nVal;
else
throw std::runtime_error("not found");
}
size_t CTable::Index(const std::string &sKey)
{
return std::hash<std::string>()(sKey) % m_table.size();
}
const CTable::SData *CTable::Lookup(const CTable::Bucket_t &b,
const std::string &sKey)
{
for (const SData &s : b)
if (s.sKey == sKey)
return &s;
return nullptr;
}
int main()
{
CTable t;
t.Add("one", 1);
t.Add("two", 2);
t.Add("three", 3);
assert(2 == t.Find("two"));
try
{
t.Find("four");
assert(false);
}
catch (std::exception &)
{
}
try
{
t.Add("two", 3);
assert(false);
}
catch (std::exception &)
{
}
return 0;
}
答案 2 :(得分:0)
正如@ user2079303所指出的,您想要的是一组Bucket **。
让我用一些图像来澄清一下:
Bucket** index = new Bucket*[<size_here>]
使您感到困惑时要记住的一件事,
说您想创建一个简单的int
数组。
您会这样做:
int* nums = new int[5];
简单地设想减少右侧的*符号的数量,因为
定义了内容类型。因此,您要存储的只是存储桶的地址。因此index
包含1个或多个指向存储桶的指针。
希望有帮助!