可伸缩的散列,使指针数组的大小加倍

时间:2014-05-13 14:36:46

标签: c++ arrays pointers hashtable

我试图在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

的转换

3 个答案:

答案 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 **。

让我用一些图像来澄清一下:

Extendible-hashing explained

Bucket** index = new Bucket*[<size_here>]使您感到困惑时要记住的一件事, 说您想创建一个简单的int数组。 您会这​​样做:

int* nums = new int[5];

简单地设想减少右侧的*符号的数量,因为 定义了内容类型。因此,您要存储的只是存储桶的地址。因此index包含1个或多个指向存储桶的指针

希望有帮助!