所以,我正在创建一个带有单独链接的自定义哈希表,我也希望为容器实现迭代器。最后使用它们时,在尝试在同一容器的两个迭代器之间使用!=
运算符时出错。
该表格式如下:vector<list<pair<K,V>>>
是否有更简单的方法来访问所有元素(因为这是我正在尝试的)?
我已经花了相当多的时间来查找我可能出错的地方,但我根本没有看到它。有谁知道为什么我收到这个错误?我非常感谢任何帮助。
哈希表的迭代器实现
class iterator{
friend class HashSeparateChaining;
public:
iterator() { } // nada
iterator(HashSeparateChaining *tp, bool end) : table(tp) {
if(end){
curr_node = table->the_lists_.back().end();
vectorPos = table->the_lists_.size()-1;
}else{
curr_node = table->the_lists_.at(0);
vectorPos = 0;
while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
++vectorPos;
curr_node = table->the_lists_.at(vectorPos);
}
}
}
iterator operator++(){
while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
++vectorPos;
curr_node = table->the_lists_.at(vectorPos);
}
return *this;
}
iterator operator++(int unusedVal){
iterator old = *this;
++(*this);
return old;
}
iterator operator==(const iterator &other) const {
return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
}
iterator operator!=(const iterator &other) const {
return !(this == other);
}
pair<Key, Value> operator*() {
return *curr_node;
}
pair<Key, Value>* operator->() {
return &(*curr_node);
}
private:
HashSeparateChaining *table;
int vectorPos;
typename list<pair<Key, Value>>::iterator curr_node;
};
class const_iterator {
friend class HashSeparateChaining;
public:
const_iterator () { }
const_iterator(HashSeparateChaining *tp, bool end) : table(tp) {
if(end){
curr_node = table->the_lists_.back().end();
vectorPos = table->the_lists_.size()-1;
}else{
curr_node = table->the_lists_.at(0);
vectorPos = 0;
while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
++vectorPos;
curr_node = table->the_lists_.at(vectorPos);
}
}
}
bool operator==(const const_iterator& other) const{
return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
}
bool operator!=(const const_iterator& other) const{
return !(*this == *other);
}
const_iterator& operator++(){
while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
++vectorPos;
curr_node = table->the_lists_.at(vectorPos);
}
return *this;
}
const_iterator operator++(int){
iterator old = *this;
++(*this);
return old;
}
pair<Key, Value> operator*() const{
return *curr_node;
}
pair<Key, Value>* operator->() const{
return &(*curr_node);
}
private:
HashSeparateChaining *table;
int vectorPos;
typename list<pair<Key, Value>>::const_iterator curr_node;
};
/********************** END OF ITERATOR CLASS **********************/
iterator begin() {
return iterator(this, false);
}
iterator end() {
return iterator(this, true);
}
const_iterator cbegin() {
return iterator(this, false);
}
const_iterator cend() {
return iterator(this, true);
}
代码崩溃
HashSeparateChaining<int,vector<string>> wordsByLength;
for( auto & str : words )
wordsByLength[ str.length( ) ].push_back( str );
for ( auto s1 = wordsByLength.begin(), e1 = wordsByLength.end(); s1 != e1; ++s1 ){
const vector<string> & groupsWords = s1->second;
int groupNum = s1->first;
for( int i = 0; i < groupNum; ++i ){
HashSeparateChaining<string,vector<string>> repToWord;
for( auto & str : groupsWords ){
string rep = str;
rep.erase( i, 1 );
repToWord[ rep ].push_back( str );
}
for ( auto s2 = repToWord.begin(), e2 = repToWord.end(); s2 != e2; ++s2 ){
const vector<string> & clique = s2->second;
if( clique.size( ) >= 2 )
for( int p = 0; p < clique.size( ); ++p )
for( int q = p + 1; q < clique.size( ); ++q ){
hash_table[ clique[ p ] ].push_back( clique[ q ] );
hash_table[ clique[ q ] ].push_back( clique[ p ] );
}
}
}
}
编译错误
test_hash_map.cc:35:67: error: value of type 'HashSeparateChaining<int, std::__1::vector<std::__1::basic_string<char>,
std::__1::allocator<std::__1::basic_string<char> > > >::iterator' is not contextually convertible to 'bool'
for ( auto s1 = wordsByLength.begin(), e1 = wordsByLength.end(); s1 != e1; ++s1 ){
^~~~~~~~
test_hash_map.cc:46:63: error: value of type 'HashSeparateChaining<std::__1::basic_string<char>,
std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > > >::iterator' is not
contextually convertible to 'bool'
for ( auto s2 = repToWord.begin(), e2 = repToWord.begin(); s2 != e2; ++s2 ){
实际哈希表实现
#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <string>
#include <algorithm>
#include <functional>
#include <utility>
using namespace std;
#include "is_prime.h"
// 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 Key, typename Value>
class HashSeparateChaining {
public:
// always initil size of 101
explicit HashSeparateChaining(int size = 101) : current_size_{0} {
the_lists_.resize( 101 ); }
~HashSeparateChaining(){
MakeEmpty();
}
bool Contains( const Key & given_key ) const {
// iterator pointing to front of the list that the item should belong to
auto & corresponding_list = the_lists_[ MyHash( given_key.first ) ];
return find( begin( corresponding_list ), end( corresponding_list ), given_key ) != end( corresponding_list );
}
void MakeEmpty( ) {
// clear every list in the vector
for( auto & curr_list : the_lists_ )
curr_list.clear( );
}
bool Insert( const pair<Key, Value> & given_pair ) {
// iterator pointing to front of the list that the item should be pushed to
auto & corresponding_list = the_lists_[ MyHash( given_pair.first ) ];
// try to find item in corresponding_list
// IF ITEM IS ALREADY THERE RETURN FALSE
if( find( begin( corresponding_list ), end( corresponding_list ), given_pair ) != end( corresponding_list) )
return false;
// ELSE INSERT ITEM TO BACK OF LIST
corresponding_list.push_back( given_pair );
// Rehash; see Section 5.5
if( ++current_size_ > the_lists_.size( ) )
Rehash( );
return true;
}
bool Insert( pair<Key, Value> && given_pair) {
// iterator pointing to front of the list that the item should be pushed to
auto & corresponding_list = the_lists_[ MyHash( given_pair.first ) ];
// try to find item in corresponding_list
// IF ITEM IS ALREADY THERE RETURN FALSE
if( find( begin( corresponding_list ), end( corresponding_list ), given_pair ) != end( corresponding_list ) )
return false;
// ELSE INSERT ITEM TO BACK OF LIST
corresponding_list.push_back( std::move( given_pair ) );
// Rehash; see Section 5.5
if( ++current_size_ > the_lists_.size( ) )
Rehash( );
return true;
}
bool Remove( const Key & given_key ) {
// where item should be if present
auto & corresponding_list = the_lists_[ MyHash( given_key ) ];
// iterator pointing to location of obj, or @ end if not present
auto itr = find( begin( corresponding_list ), end( corresponding_list ), given_key );
if( itr == end( corresponding_list ) )
return false;
corresponding_list.erase( itr );
--current_size_;
return true;
}
Value& operator[](Key given_key){
auto & corresponding_list = the_lists_[ MyHash( given_key ) ];
for(auto &curr_pair : corresponding_list)
if(curr_pair.first == given_key)
return curr_pair.second;
// if item not currently in container
corresponding_list.push_back(make_pair(given_key, Value()));
return corresponding_list.back().second;
}
/******************** START OF ITERATOR SUPPORT ********************/
class iterator{
friend class HashSeparateChaining;
public:
iterator() { } // nada
iterator(HashSeparateChaining *tp, bool end) : table(tp) {
if(end){
curr_node = table->the_lists_.back().end();
vectorPos = table->the_lists_.size()-1;
}else{
curr_node = table->the_lists_.at(0);
vectorPos = 0;
while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
++vectorPos;
curr_node = table->the_lists_.at(vectorPos);
}
}
}
iterator operator++(){
while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
++vectorPos;
curr_node = table->the_lists_.at(vectorPos);
}
return *this;
}
iterator operator++(int unusedVal){
iterator old = *this;
++(*this);
return old;
}
iterator operator==(const iterator &other) const {
return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
}
iterator operator!=(const iterator &other) const {
return !(this == other);
}
pair<Key, Value> operator*() {
return *curr_node;
}
pair<Key, Value>* operator->() {
return &(*curr_node);
}
private:
HashSeparateChaining *table;
int vectorPos;
typename list<pair<Key, Value>>::iterator curr_node;
};
class const_iterator {
friend class HashSeparateChaining;
public:
const_iterator () { }
const_iterator(HashSeparateChaining *tp, bool end) : table(tp) {
if(end){
curr_node = table->the_lists_.back().end();
vectorPos = table->the_lists_.size()-1;
}else{
curr_node = table->the_lists_.at(0);
vectorPos = 0;
while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
++vectorPos;
curr_node = table->the_lists_.at(vectorPos);
}
}
}
bool operator==(const const_iterator& other) const{
return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
}
bool operator!=(const const_iterator& other) const{
return !(*this == *other);
}
const_iterator& operator++(){
while(curr_node == table->the_lists_.at(vectorPos).end() && vectorPos < table->the_lists_.size()){
++vectorPos;
curr_node = table->the_lists_.at(vectorPos);
}
return *this;
}
const_iterator operator++(int){
iterator old = *this;
++(*this);
return old;
}
pair<Key, Value> operator*() const{
return *curr_node;
}
pair<Key, Value>* operator->() const{
return &(*curr_node);
}
private:
HashSeparateChaining *table;
int vectorPos;
typename list<pair<Key, Value>>::const_iterator curr_node;
};
/********************** END OF ITERATOR CLASS **********************/
iterator begin() {
return iterator(this, false);
}
iterator end() {
return iterator(this, true);
}
const_iterator cbegin() {
return iterator(this, false);
}
const_iterator cend() {
return iterator(this, true);
}
/********************* END OF ITERATOR SUPPORT *********************/
private:
vector<list<pair<Key, Value>>> the_lists_;
int current_size_;
void Rehash( ) {
vector<list<pair<Key, Value>>> old_lists = the_lists_;
// Create new double-sized, empty table
the_lists_.resize( PrimeProject::NextPrime( 2 * the_lists_.size( ) ) );
for( auto & curr_list : the_lists_ )
curr_list.clear( );
// Copy table over
current_size_ = 0;
for( auto & curr_list : old_lists )
for( auto & item_in_list : curr_list )
insert( std::move( item_in_list ) );
}
size_t MyHash( const Key & given_key ) const {
static hash<Key> hf;
return hf( given_key ) % the_lists_.size( );
}
};
#endif
答案 0 :(得分:0)
我认为你为迭代器实现的运算符==和!=时犯了一个错误:当它应该是 bool 时,你输入的返回类型是 iterator 。 / p>
iterator operator==(const iterator &other) const {
return table == other.table && vectorPos == other.vectorPos && curr_node == other.curr_node;
}
iterator operator!=(const iterator &other) const {
return !(this == other);
}
来自http://en.cppreference.com/w/cpp/language/operator_comparison
的有趣说明当内置运算符返回bool时,大多数用户定义的重载也返回bool,因此用户定义的运算符可以与内置函数相同的方式使用。但是,在用户定义的运算符重载中,任何类型都可以用作返回类型(包括void)。