打开散列c ++时的“不完整类型”

Posted

技术标签:

【中文标题】打开散列c ++时的“不完整类型”【英文标题】:"Incomplete Type" when open hashing c++ 【发布时间】:2014-11-29 20:25:10 【问题描述】:

我是 C++ 新手,遇到了一个我以前从未见过的错误。我正在尝试通过使用哈希表(开放哈希)的回溯算法进行搜索。

在进行递归调用之前,我正在搜索哈希表以查看之前是否已搜索过当前位置(并且已失败),然后在递归调用返回时将整数向量“B”插入哈希表false 这样可以避免以后搜索相同的位置。

这是我程序调用文件中的函数以进行哈希处理:

bool open_hash_solve (vector<int> B, vector<Move> & MS, vector<Move> & TMS, OpenHashTable<vector<int>> & H) 

  if (solved(B))
    return true;

  vector<Move> curr = currentMoves(B, TMS);

  for (int m = 0; m < curr.size(); m++) 

    vector<int> moveMade = makeMove(B, curr[m]);

    if (!H.contains(moveMade))

      if (open_hash_solve(moveMade, MS, TMS, H))

        MS.insert(MS.begin(), curr[m]);
        return true;
      
      else
        H.insert(moveMade);
    
  
  return false;

头文件分离教科书链接:

#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H

#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;


int nextPrime( int n );

// SeparateChaining Hash table class
//
// CONSTRUCTION: an approximate initial size or default of 101
//
// ******************PUBLIC OPERATIONS*********************
// bool insert( x )       --> Insert x
// bool remove( x )       --> Remove x
// bool contains( x )     --> Return true if x is present
// void makeEmpty( )      --> Remove all items

template <typename HashedObj>
class OpenHashTable

 public:
  explicit OpenHashTable( int size = 101 ) : currentSize 0 
   theLists.resize( 101 ); 

  bool contains( const HashedObj & x ) const
  
    auto & whichList = theLists[ myhash( x ) ];
    return find( begin( whichList ), end( whichList ), x ) != end( whichList );
  

  void makeEmpty( )
  
    for( auto & thisList : theLists )
      thisList.clear( );
  

  bool insert( const HashedObj & x )
  
    auto & whichList = theLists[ myhash( x ) ];
    if( find( begin( whichList ), end( whichList ), x ) != end( whichList) )
      return false;
    whichList.push_back( x );

    // Rehash; see Section 5.5
    if( ++currentSize > theLists.size( ) )
      rehash( );

    return true;
   

  bool insert( HashedObj && x )
  
    auto & whichList = theLists[ myhash( x ) ];
    if( find( begin( whichList ), end( whichList ), x ) != end( whichList ) )
      return false;
    whichList.push_back( std::move( x ) );

    // Rehash; see Section 5.5
    if( ++currentSize > theLists.size( ) )
      rehash( );

    return true;
  

  bool remove( const HashedObj & x )
  
    auto & whichList = theLists[ myhash( x ) ];
    auto itr = find( begin( whichList ), end( whichList ), x );

    if( itr == end( whichList ) )
      return false;

    whichList.erase( itr );
    --currentSize;
    return true;
  

 private:
  vector<list<HashedObj>> theLists;   // The array of Lists
  int  currentSize;

  void rehash( )
  
    vector<list<HashedObj>> oldLists = theLists;

    // Create new double-sized, empty table
    theLists.resize( nextPrime( 2 * theLists.size( ) ) );
    for( auto & thisList : theLists )
      thisList.clear( );

    theLists.resize( nextPrime( 2 * theLists.size( ) ) );
    for( auto & thisList : theLists )
      thisList.clear( );

    // Copy table over
    currentSize = 0;
    for( auto & thisList : oldLists )
      for( auto & x : thisList )
        insert( std::move( x ) );
  

  size_t myhash( const HashedObj & x ) const
  
    static hash<HashedObj> hf;  ***** ERROR HERE *****
    return hf( x ) % theLists.size( );
  
;

#endif

我的错误:

SeparateChaining.h: In instantiation of ‘size_t OpenHashTable<HashedObj>::myhash(const HashedObj&) const [with HashedObj = std::vector<int>; size_t = long unsigned int]’:

SeparateChaining.h:33:44:   required from ‘bool OpenHashTable<HashedObj>::contains(const HashedObj&) const [with HashedObj = std::vector<int>]’

movetest1.cpp:107:29:   required from here

SeparateChaining.h:106:34: error: ‘std::hash<std::vector<int> > hf’ has incomplete type
 static hash<HashedObj> hf;
                        ^

我该如何解决这个问题? 如果我的描述没有意义或需要澄清,请告诉我。提前致谢!

【问题讨论】:

你能把调用编译器的那一行(带所有参数)放在一边吗?如果还可以告诉编译器版本... g++ -g -std=c++11 movetest1.cpp @lrleon 显然,编译器不知道类型 hash。我猜这是散列函数,它应该返回一个 size_t 类型的值。但类型是 hash 而不是 size_t。下一行也很奇怪,因为它执行模块(%),它要求类型 hash 可以转换为整数。是这样吗?验证编译器是否知道该类型 (hash) 我相信类型 hash 被转换成整数@lrleon 我将 myhash 修改为: int myhash( const HashedObj & x ) const int hashVal = hash( x ) ; hashVal %= theLists.size( ); if( hashVal ::myhash(const HashedObj&) const':SeparateChaining.h:111:23:错误:在'('令牌int hashVal =之前缺少模板参数哈希(x);@lrleon 【参考方案1】:

原因是std::hash 没有为std::vector 定义,std::vector&lt;bool&gt; 除外。它仅为basic types and select library types 定义。您必须实现自己的哈希算法。

关于您的最后一条评论,hash( x ) 是无效代码,因为std::hash 是类模板,而不是函数模板。

您也不能为std::hash&lt;std::vector&lt;int&gt;&gt; 编写自己的特化,因为std::vector&lt;int&gt; 不是用户定义的类型。

适当的解决方案是C++ standard library - OpenHashTable 应该允许其用户指定散列算法:

template<typename HashedObj, typename Hash = std::hash<HashedObj>>
class OpenHashTable 
    // ...
    size_t myhash(const HashedObj& x) const 
        static Hash hf;
        return hf(x) % theLists.size();
    
;

所以你可以这样使用它:

struct my_vector_int_hash 
    size_t operator()(const std::vector<int>& v) const 
        // your code here
    
;

OpenHashTable<std::vector<int>, my_vector_int_hash> hashtable;

更新:只要讨论过你是否可以专攻std::hash&lt;std::vector&lt;int&gt;&gt;,这就是为什么不允许你这样做。

[namespace.std]/1 说:

除非另有说明,否则如果 C++ 程序将声明或定义添加到命名空间 std 或命名空间 std 内的命名空间,则其行为未定义。只有当声明依赖于用户定义的类型并且特化满足原始模板的标准库要求并且没有明确禁止时,程序才能将任何标准库模板的模板特化添加到命名空间std

std::vector&lt;int&gt; 不是用户定义的类型,也不依赖于任何用户定义的类型,因此这种特化是非法的,会导致未定义的行为。

【讨论】:

如下所述,您可以专门化 hash<:vector>>。它可能不那么优雅,但你可以。我检查了@Savin @lrleon 这是未定义的行为。 这样吗?模板> class OpenHashTable ... int myhash( const HashedObj & x ) const int hashVal = hash( x ) ; hashVal %= theLists.size( ); if( hashVal 我不太明白你的回答 @dave1234 我添加了myhash 的实现应该如何

以上是关于打开散列c ++时的“不完整类型”的主要内容,如果未能解决你的问题,请参考以下文章

使用 32 位散列时的冲突概率

不可散列的类型:加入 PySpark RDD 时的“列表”

散列函数的安全性问题

2016011998 张舒凯 散列函数的应用及其安全性

散列函数的应用及其安全性 周紫伊2016012043

散列查找-平方探测法