困惑在C ++中实现rehash()函数

时间:2013-07-30 03:11:05

标签: c++ hashtable

我的目标是为我在C ++模板类中编写的哈希表实现rehash()方法。但是,我很困惑究竟是什么我可以哈希,因为这个方法只知道类型作为泛型。据我所知,这与Java泛型不同

我对java的理解...... 在Java中,由于每个对象都继承了hashCode()方法,因此我们可以覆盖此方法。如果在java中编写通用哈希表,那么在rehash()期间,可以简单地调用hashCode()方法来返回值。这可以通过tableSize进行修改。无痛

回到C ++ ...... 因为我不相信我可以简单地在我的C ++泛型上调用hashCode()方法,也不能访问泛型类型的数据成员,所以我不知道我可以重新编写什么。

我的C ++中的泛型类型是否有可能继承一个抽象类,所以我可以强制使用虚拟hashcode()= 0方法? 或者模板类中的哈希函数是否依赖于其他类型的非数据库哈希?

试图尽可能清楚。感谢任何能指出我正确方向或提供指导的人。

1 个答案:

答案 0 :(得分:1)

注意:当然,我认为实现哈希表的目标是出于学习目的。如果没有,请使用std::unordered_map

这里最重要的一点是你已经注意到了:模板和泛型不是一回事。 (好吧,java泛型只是一个花哨的语法糖工具,多亏了类型擦除,但它的另一个故事)。

C ++模板可以为模板的每个不同时刻编写一个类的版本。也就是说,如果在程序中使用std::vector<int>std::vector<bool>,编译器会生成类向量的代码,其中int为类型,类向量为bool作为类型。

模板最强大的一个方面是每个与类型相关的操作都在编译时进行评估。也就是说,每个模板即时,别名,typedef等都是在编译时完成的。您在运行时获得的代码是不同模板实例的最终生成类的复合。所以你不要在运行时考虑类型,比如像java或C#这样的OO语言,你考虑编译时。 编译结束时必须解决Everithing

现在我们看看你的问题:
您希望类型的“hashable”“接口”能够调用哈希表中的哈希函数。 这可以通过两种方式完成:

基于会员功能的方式:

解决问题的一种方法是假设您的类型具有hash()公共成员函数(如Java中的getHashCode(),继承自Object)。 因此,在哈希表实现中,您使用此哈希函数,就好像元素具有它一样。不要担心传递的类型。 事实是,如果您这样做,并且您传递的类型作为模板argumment没有公共哈希成员函数,则无法实例化模板。中提琴!
将模板视为契约:您在模板中编写完全通用的代码。传递给模板的类型必须填写合同。也就是说,必须拥有你认为拥有的一切。

这种方法的问题是hashmap中使用的任何类型都必须具有哈希公共成员函数。请注意,您不能以这种方式在hashmap中使用基本类型。

基于Functor的方式:

仿函数 是一个充当函数的类。也就是说,可以使用该类的实例,因为它是一个函数。例如:

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);
}

但仿函数最重要的用途是仿函数是类的实例,因此可以作为argumments传递给其他站点。也就是说,函子充当高级函数指针。

这用于通用STL算法,如std::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 ++模板,您可以编写特殊情况。您使用显式类型作为模板argumment显式编写模板类。这称为"template specialization"。实际上,“使用布局大小写的位”示例正是std::vector does

在我们的例子中,如果我们有一个哈希函子的声明:

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。请注意,libray具有一组基本类型的内置哈希特化。