在C++中实现rehash()函数时感到困惑
Confused implementing a rehash() function in C++
我的目标是为我在C++模板类中编写的哈希表实现一个rehash()方法。然而,我很困惑我到底可以散列什么,因为这个方法只知道类型是泛型。据我所知,这与Java泛型不同
我对java的理解。。。在Java中,由于每个对象都继承了hashCode()方法,所以我们可以覆盖这个方法。如果用java编写通用哈希表,那么在rehash()过程中,可以简单地调用hashCode()方法来返回值。这可以通过tableSize进行修改。无痛
回到C++。。。由于我不相信我可以简单地在C++泛型上调用hashCode()方法,也不能访问泛型类型的数据成员,所以我不知道我可以在什么上重新散列
我在C++中的泛型类型有可能继承一个抽象类,这样我就可以强制使用一个虚拟hashcode()=0方法吗?或者模板类中的哈希函数依赖于其他类型的非数据成员哈希?
尽量说清楚。感谢任何能为我指明正确方向或提供指导的人。
注意:当然,我认为实现哈希表的目标是为了学习。如果没有,请使用std::unordered_map
。
这里最重要的一点是您已经注意到的:模板和泛型不是一回事。(好吧,由于类型擦除,java泛型只是一个奇特的语法糖工具,但那是另一回事)。
C++模板为模板的每个不同实例化编写一个类的版本。也就是说,如果在程序中使用std::vector<int>
和std::vector<bool>
,编译器将为类型为int的类向量和类型为bool的类向量生成代码。
模板最强大的方面之一是,每个与类型相关的操作都在编译时进行评估。也就是说,每个模板实例化、别名、typedef等都是在编译时完成的。您在运行时获得的代码是为不同模板实例最终生成的类的组合。因此,您不会像在java或C#这样的OO语言中那样在运行时考虑类型,而是考虑编译时编译结束时必须解决Everithing。
现在我们来看一下您的问题:
您希望为您的类型提供一个"hashable"接口",以调用哈希表中的哈希函数。这可以通过两种方式实现:
基于成员功能的方式:
解决问题的一种方法是假设您的类型有一个hash()
公共成员函数(就像java中的getHashCode()
一样,它是从Object继承的)。因此,在您的哈希表实现中,您使用这个哈希函数,就好像元素拥有它一样。不要担心传递的类型。事实是,如果你这样做,并且你传递了一个没有公共散列成员函数的类型作为模板argument,那么模板就无法实例化。Violá
将模板视为合同:在模板中编写一个完全通用的代码。传递给模板的类型必须完全填充合同。也就是说,必须拥有你认为他们拥有的一切。
这种方法的问题在于,哈希映射中使用的任何类型都必须具有哈希公共成员函数。请注意,通过这种方式,您不能在hashmap中使用基本类型。
基于函数的方式:
函子 是一个充当函数的类。也就是说,该类的实例可以像函数一样使用。例如:
template<typename T>
struct add
{
T operator()(const T& a , const T& b)
{
return a + b;
}
};
您可以按如下方式使用此函子:
int main()
{
add<int> adder;
int a = 1 , b = 2;
int c = adder(a,b);
}
但函子最重要的用途是基于函子是类的实例,因此可以作为自变量传递到其他站点。也就是说,函子充当高级函数指针。
这用于通用STL算法,如std::find_if
:Find if,用于根据搜索标准查找指定间隔的元素。该标准通过一个充当布尔谓词的函子传递。例如:
class my_search_criteria
{
bool operator()(int element)
{
return element == 0;
}
};
int main()
{
std::vector<int> integers = { 5 , 4 , 3 , 2 , 1 , 0 };
int search_result = std::find_if( std::begin( integers ) , std::end( integers ) , my_search_criteria() );
}
但是,函子如何帮助解决您的问题
您可以实现一个充当哈希函数的通用函子:
template<typename T>
struct hash
{
unsigned int operator()(const T& element)
{
return /* hash implementation */
}
};
并在您的哈希表类中使用它:
template<typename T>
class hachtable
{
private:
hash<T> hash_function;
std::vector<T> _container;
void add(const T& element)
{
_container.insert(std::begin( _container ) + hash_function( element ) , element);
}
};
请注意,您需要为元素的类型实现散列。C++模板允许您编写模板的特殊显式事例。例如,您编写了一个泛型数组类,并注意到如果元素的类型是布尔型的,那么将布尔型存储为数字位可能会更高效,以减少内存消耗。使用C++模板,您可以编写特殊情况。您使用显式类型显式编写模板类作为template argument。这被称为"模板专业化"。事实上,"将位用于布尔大小写"的例子正是std::vector
所做的。
在我们的例子中,如果我们有一个散列函子的声明:
template<typename T>
struct hash;
我们需要为您将在hashmap中使用的每种类型进行专门化。例如,无符号整数的特殊化:
template<>
struct hash<unsigned int>
{
unsigned int operator()(unsigned int element)
{
return element;
}
};
基于函子的方法正是C++标准库所做的。它有一个散列函子std::hash
的定义,并在散列表实现中使用它,如std::unordered_map
。请注意,库中有一组针对基本类型的内置散列专门化。
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗