我正在使用C ++中的简单哈希表。我有方法插入,删除和搜索指定键的哈希表。我知道C ++ map STL容器可以处理我的情况,但我想把自己编写为一个教育练习。
基本上我有一个哈希表,它将采用一个字符串并将其映射到其他字符串的向量。这在方法中很容易实现,因为调用.Add()或.Delete()将按预期运行。但是,我想为能够对向量执行这些操作的类创建一个重载的[]运算符。
例如,如果我想在向量中添加一个项目,我可以这样写:
hashTable[string1] = newString;
这会将新字符串设置为vector的成员。删除和搜索也是如此。
hashTable[string1] = ""; cout << hashTable[string1] << endl;
我的主要问题是我不知道如何重载[]
运算符以获得此功能。我现在编写了这个功能。它适用于基本的1到1字符串匹配,但不适用于字符串到矢量匹配。
//Return a reference to a vector to update then reassign? vector& HashClass::operator[](const string index) { assert(size >= 0 && size < maxSize); Hash(key); return hashTable[index]; }
我认为我最常想的是有一个向后返回的想法,以后需要分配。作为用户,我会发现这个kludgy。
答案 0 :(得分:0)
在C ++中,[]
对关联容器的访问通常被赋予默认的语义 - 构造映射类型的对象,使用键插入它,并返回对插入的映射对象的引用。
因此,您的operator[]
将实现为:
string& HashClass::operator[](const string index)
{
assert(size >= 0 && size < maxSize);
Hash(key);
vector &v = hashTable[index];
if (index in v) {
...
} else {
v.push_back(string());
return v.back();
}
}
答案 1 :(得分:0)
这个问题与另一个问题密切相关:行为是什么 当你访问一个非存在的值而不是一个时,你想要的 分配?换句话说,当你写作时你想要发生什么:
std::cout << hashTable[string] << std::endl;
表中没有和string
?
有两种可能的方法:你可以认为它是一个错误,并且 抛出异常,或中止或类似的东西;或者你可以回来 某种默认值,使用默认构造函数构建,或由提供者提供 客户早些时候。
标准地图和unordered_map采用第二种方法,使用
用于构造新值的默认构造函数。这允许非常简单
解决方案:如果operator[]
不存在,则插入它,初始化它
使用默认值。然后你返回一个引用;
hashTable[string] = newString;
通过引用来指定
已存在的价值。
在许多使用案例中,第一种方法更可取(也许是一种
contains
功能,因此您可以预先测试是否operator[]
会找到或不会找到的东西)。要实现第一种方法,您必须
首先为每种访问类型实现特定的功能:
template <typename Key, typename Value>
class HashTable
{
public:
Value* get( Key const& key ) const;
void set( Key const& key, Value const& value );
};
(我通常将这些公开;没有理由禁止他们使用 客户。)
然后,您定义operator[]
以返回代理,如下所示:
template <typename Key, typename Value>
class HashTable
{
public:
class Proxy
{
HashTable* myOwner;
Key myKey;
public:
Proxy( HashTable* owner, Key const& key )
: myOwner( owner )
, myKey( key )
{
}
operator Value const&() const
{
Value const* result = myOwner->get( myKey );
if ( result == NULL ) {
// Desired error behavior here...
}
return *result;
}
Proxy const& operator==( Value const& value ) const
{
myOwner->set( myKey, value );
return *this;
}
};
Value* get( Key const& key ) const;
void set( Key const& key, Value const& value );
Proxy operator[]( Key const& key )
{
return Proxy( this, key );
}
};
因此,当你写:
hashTable[key] = newString;
,代理operator=
将调用hashTable.put( key, newString )
;
但是,在其他上下文中,它将调用隐式类型转换
代理,调用hashTable.get( key )
。
在某些情况下,即使您希望返回默认值,也可能是
最好使用此解决方案:不需要get
函数
在哈希表中插入任何内容,因此表格不会填满
所有未命中,你可以重载operator[]
const
,所以
您也可以在const
哈希表上使用它。而且,它没有
要求值类型具有默认构造函数。
对于使用的解决方案,它确实有一个缺点
标准;由于您无法重载operator.
,因此无法创建代理
表现得像一个参考,像:
hashTable[string].someFunction();
不行。解决方法是在代理中重载operator->
,但是
这会导致一种不自然的语法:
hashTable[string]->someFunction(); // But the hash table contains
// values, not pointers!!!
(不要因隐式转换为引用而误导
表达式中a
不会考虑隐式转换
a.b
。)