C++ resize 2d vector where function is const - c++

I create a 2D vector (0,0) and would like to resize it (n,m), however, my resize function must remain const
I have tried doing
void resize(int row, int col) const
{
array.resize(row, vector<int>(col));
}
but keep getting
passing ‘const std::vector<std::vector<int>, std::allocator<std::vector<int> > >’ as ‘this’ argument discards qualifiers
How can I do this?
Matrix.h
#pragma once
#include <vector>
using namespace std;
template <typename Object>
class matrix
{
public:
matrix(int rows, int cols) : array{ rows } {
for (auto& thisRow : array)
thisRow.resize(cols);
}
matrix( initializer_list<vector<Object>> lst ) : array( lst.size( ) )
{
int i = 0;
for( auto & v : lst )
array[ i++ ] = std::move( v );
}
matrix( const vector<vector<Object>> & v ) : array{ v } {}
matrix( vector<vector<Object>> && v ) : array{ std::move( v ) } {}
matrix() {}
const vector<Object> & operator[]( int row ) const
{
return array[ row ];
}
vector<Object> & operator[]( int row )
{
return array[ row ];
}
int numrows() const
{
return array.size( );
}
int numcols() const
{
return numrows( ) ? array[ 0 ].size( ) : 0;
}
void resize(int row, int col) const
{
array.resize(row, vector<int>(col));
}
private:
vector<vector<Object>> array;
};
main.cpp
matrix<int> mat = matrix<int>();
cout << "Zero-parameter matrix (rows,cols) = (" << mat.numrows() << "," << mat.numcols() << ")" << endl;
mat.resize(4, 3);
cout << "Resized matrix to 4x3" << endl;
cout << mat << endl;
mat[2][1] = 12;
cout << "Modified (2,1)" << endl;
cout << mat << endl;

When you put const on the end of the function there, you're saying the implicit this is const. That is, you're promising not to modify the state of the object this function is being called on.
But isn't the whole point of calling resize() to modify the state of the object? If I were you, I'd take the const off of there.
In other words, you have two options: either keep your promise to not change the state of the object (perhaps by returning a resized copy?), or lose the const.

Related

C++ overload [][] for a list

I got a class Matrix with a member std::list<Element> listMatrix;. Element is a a class with 3 int members line, column, value. I save in the list, elements of a matrix that are not 0 by saving the line, column and the value of the respectively element. I want to overload the operator [][] so I can do something like Matrix a; a[2][3] = 5;. I know you can't overload [][] directly.
Do overload Element& operator()(int, int) (and the const variant) so you can write
matrix(2, 3) = 5;
If you absolutely need the [2][3] syntax, you'd need to define a proxy class so matrix[2] return a proxy value and proxy[3] return the desired reference. But it comes with a lot of problems. The basic idea would be:
class naive_matrix_2x2
{
int data[4];
struct proxy
{
naive_matrix_2x2& matrix;
int x;
int& operator[](int y) { return matrix.data[x*2+y]; }
};
public:
proxy operator[](int x) { return {*this, x}; }
};
Full demo: https://coliru.stacked-crooked.com/a/fd053610e56692f6
The list is not a suitable container for using the subscript operator because it has no direct access to its elements without moving an iterator through the list.
So the operator will be inefficient.
It is better to use the standard container std::vector that already has the subscript operator.
Nevertheless answering your question the operator can be defined the following way. You can add to the operators an exception then an index will point outside the list.
#include <iostream>
#include <list>
struct A
{
int x, y, z;
int & operator []( size_t n )
{
return n == 0 ? x : n == 1 ? y : z;
}
const int & operator []( size_t n ) const
{
return n == 0 ? x : n == 1 ? y : z;
}
};
struct B
{
std::list<A> lst;
A & operator []( size_t n )
{
auto it = std::begin( lst );
for ( ; n; n-- ) std::advance( it, 1 );
return *it;
}
const A & operator []( size_t n ) const
{
auto it = std::begin( lst );
for ( ; n; n-- ) std::advance( it, 1 );
return *it;
}
};
int main()
{
B b = { { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } } };
std::cout << b[0][0] << '\n';
std::cout << b[0][1] << '\n';
std::cout << b[0][2] << '\n';
b[2][1] += 20;
std::cout << b[2][1] << '\n';
}
The program output is
1
2
3
28

Adding contents to a variadic template type after instantiation

Current Source
At this point in my code I have this variadic template class:
template<typename ClassType, std::size_t... Args>
class Matrix {
private:
DimensionPack<Args...> dp;
public:
Matrix<ClassType, Args...>(){} // Default
// Public Access Members To Get Information From the DimensionPack which is based
// Not On The Type But Based On The Amount & Values Of This Template's Variadic Parameters
std::vector<unsigned int>& getDimensions() { return dp.dimensions; }
std::vector<unsigned int>& getEvenOrOdd() { return dp.even_or_odd; }
const unsigned int getNumberOfDimensions() const { return dp.total_dimensions; }
const unsigned int getTotalNumElements() const { return dp.total_elements; }
};
It uses this class and structure to do the needed calculations based on its variadic parameter list of values passed in (std::size_t...).
const unsigned int EVEN = 0;
const unsigned int ODD = 1;
struct MatrixDimensionOddOrEven {
const unsigned int even_or_odd;
explicit MatrixDimensionOddOrEven( unsigned int odd_or_even ) : even_or_odd( test( odd_or_even ) ) {}
private:
const unsigned int test( unsigned int value ) const {
if ( value == 0 ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << "invalid number: " << value << " must be >= 1.";
Logger::log( strStream, Logger::TYPE_ERROR );
throw ExceptionHandler( strStream );
}
return ( ((value % 2) == 0) ? EVEN : ODD );
}
}; typedef MatrixDimensionOddOrEven MatDimOddEven;
template <std::size_t... Dims>
class DimensionPack {
public:
std::vector<std::size_t> dimensions;
std::vector<unsigned int> even_or_odd;
const std::size_t total_dimensions = sizeof...(Dims);
const std::size_t total_elements = countElements();
public:
DimensionPack() : dimensions{Dims...},
even_or_odd{ MatrixDimensionOddOrEven{Dims}.even_or_odd...} {
}
private:
std::size_t countElements() {
std::size_t val = 1; // Don't Init to 0 otherwise multiplication won't work here!
for ( std::size_t n = 0; n < dimensions.size(); n++ ) {
val *= dimensions.at( n );
}
return val;
}
};
At this point in my Matrix class I am able to successfully compile and get the results that are expected such as in these cases:
Examples Of Use:
Matrix<float, 1> mat1; // Single Element Matrix - Considered A Scalar Type
Matrix<float, 1,1...> mat1...; // Again - Single Element Matrix - Considered A Scalar Type
Matrix<float, n, m, 1, p> matNM1P; // Where n,m,p are > 1 makes that field of dimensionality flat such as a linear array or vector.
Matrix<float, 2,2> mat2x2; // creates a 2x2 Matrix with 4 elements of type float
Matrix<int, 3,3,3> mat3x3x3; // creates a 3x3x3 Volumetric Matrix with 27 elements of type int.
Matrix<type,n...> mat_multidimensional; // creates any higher order dimension of type.
I can pass them to this function to get the correct results and values:
template<typename type, std::size_t... dims>
void testMatrix( Matrix<type, dims...> matrix ) {
std::cout << "The Matrix Has " << matrix.getNumberOfDimensions() << " Total Dimensions:\n";
std::cout << "The Dimensions Are:\n";
for ( unsigned u = 0; u < matrix.getDimensions().size(); u++ ) {
std::cout << matrix.getDimensions()[u] << " ";
}
std::cout << std::endl;
std::cout << "The even and odd of each dimension are:\n";
for ( unsigned u = 0; u < matrix.getEvenOrOdd().size(); u++ ) {
std::cout << matrix.getEvenOrOdd()[u] << " ";
}
std::cout << std::endl;
std::cout << "The Matrix Has " << matrix.getTotalNumElements() << " total elements.\n\n";
}
Making my main.cpp look like this:
#include <Matrix.h>
int main() {
Matrix<float, 2, 3, 4> mat;
testMatrix( mat );
Matrix<int, 7, 9, 13, 15, 17> mat2;
testMatrix( mat2 );
Matrix<double, 255,255,255,255,255,255,255,255,255> mat9;
testMatrix( mat9 );
return 0;
}
Everything up to this point works fine and the results are expected.
The Goal
As you can see my Matrix class has a default constructor and now it is time to add contents to it. And this is where I'm sort of stuck.
For Example: If a user did the following they would have:
Matrix<float, 4,4,4> mat4x4x4; // A 3D Volumetric Matrix With 256 Elements
Matrix<float, 2,3,5> mat2x3x5; // A 3D Volumetric Matrix With 30 Elements
Matrix<float, 5,7,8,10> mat5x7x8x10; // A 4D Volumetric Matrix With 2800 Elements
Should I just accept a single vector<type> that has a fixed size that
matches the total amount of elements and create an indexing scheme?
Should I have nested <vector<vector<type>> where the amount of nested vectors matches the number of dimensions if the automation of doing such a thing can be done?
Should I create a helper structure that will nest up to 3 nested vectors then repeat that process if the automation of it can be done?
This is where I'm looking for good sound advice as to what my options should be and how it can easily be done.

Different return and coordinate types in nanoflann radius search

I'm trying to use nanoflann in a project and am looking at the vector-of-vector and radius search examples.
I can't find a way to perform a radius search with a different data type than the coordinate type. For example, my coordinates are vectors of uint8_t; I am trying to input a radius of type uint32_t with little success.
I see in the source that the metric_L2 struct (which I am using for distance) uses the L2_Adaptor with two template parameters. L2_Adaptor itself takes three parameters, with the third defaulted to the first, which seems to be the problem if I am understanding the code correctly. However, trying to force use of the third always results in 0 matches in the radius search.
Is there a way to do this?
Edit: In the same code below, everything works. However, if I change the search_radius (and ret_matches) to uint32_t, the radiusSearch method doesn't work.
#include <iostream>
#include <Eigen/Dense>
#include <nanoflann.hpp>
typedef Eigen::Matrix<uint8_t, Eigen::Dynamic, 1> coord_t;
using namespace nanoflann;
struct Point
{
coord_t address;
Point() {}
Point(uint8_t coordinates) : address(coord_t::Random(coordinates)) {}
};
struct Container
{
std::vector<Point> points;
Container(uint8_t coordinates, uint32_t l)
: points(l)
{
for(auto& each_location: points)
{
each_location = Point(coordinates);
}
}
};
struct ContainerAdaptor
{
typedef ContainerAdaptor self_t;
typedef nanoflann::metric_L2::traits<uint8_t, self_t>::distance_t metric_t;
typedef KDTreeSingleIndexAdaptor<metric_t, self_t, -1, size_t> index_t;
index_t *index;
const Container &container;
ContainerAdaptor(const int dimensions, const Container &container, const int leaf_max_size = 10)
: container(container)
{
assert(container.points.size() != 0 && container.points[0].address.rows() != 0);
const size_t dims = container.points[0].address.rows();
index = new index_t(dims, *this, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size));
index->buildIndex();
}
~ContainerAdaptor()
{
delete index;
}
inline void query(const uint8_t *query_point, const size_t num_closest, size_t *out_indices, uint32_t *out_distances_sq, const int ignoreThis = 10) const
{
nanoflann::KNNResultSet<uint32_t, size_t, size_t> resultSet(num_closest);
resultSet.init(out_indices, out_distances_sq);
index->findNeighbors(resultSet, query_point, nanoflann::SearchParams());
}
const self_t& derived() const
{
return *this;
}
self_t& derived()
{
return *this;
}
inline size_t kdtree_get_point_count() const
{
return container.points.size();
}
inline size_t kdtree_distance(const uint8_t *p1, const size_t idx_p2, size_t size) const
{
size_t s = 0;
for (size_t i = 0; i < size; i++)
{
const uint8_t d = p1[i] - container.points[idx_p2].address[i];
s += d * d;
}
return s;
}
inline coord_t::Scalar kdtree_get_pt(const size_t idx, int dim) const
{
return container.points[idx].address[dim];
}
template <class BBOX>
bool kdtree_get_bbox(BBOX & bb) const
{
for(size_t i = 0; i < bb.size(); i++)
{
bb[i].low = 0;
bb[i].high = UINT8_MAX;
}
return true;
}
};
void container_demo(const size_t points, const size_t coordinates)
{
Container s(coordinates, points);
coord_t query_pt(coord_t::Random(coordinates));
typedef ContainerAdaptor my_kd_tree_t;
my_kd_tree_t mat_index(coordinates, s, 25);
mat_index.index->buildIndex();
const uint8_t search_radius = static_cast<uint8_t>(100);
std::vector<std::pair<size_t, uint8_t>> ret_matches;
nanoflann::SearchParams params;
const size_t nMatches = mat_index.index->radiusSearch(query_pt.data(), search_radius, ret_matches, params);
for (size_t i = 0; i < nMatches; i++)
{
std::cout << "idx[" << i << "]=" << +ret_matches[i].first << " dist[" << i << "]=" << +ret_matches[i].second << std::endl;
}
std::cout << std::endl;
std::cout << "radiusSearch(): radius=" << +search_radius << " -> " << +nMatches << " matches" << std::endl;
}
int main()
{
container_demo(1e6, 32);
return 0;
}
More info: so it seems that the distance type, which the third parameter of the L2_Adaptor, must be a signed type. Changing the metric_t typedef to the following solves the problem if search_radius and ret_matches are also changed to int64_t.
typedef L2_Adaptor<uint8_t, self_t, int64_t> metric_t;

HashTable... error: static assertion failed: std::hash is not specialized for this type

I posted earlier today and was able to work out a lot of my errors. However, I still have one error that I cannot figure out for the life of me. I'm basically just trying to insert a Symbol object into a HashTable and I'm constantly getting this message back:
In file included from /opt/local/include/gcc47/c++/bits/basic_string.h:3032:0,
from /opt/local/include/gcc47/c++/string:54,
from /opt/local/include/gcc47/c++/bits/locale_classes.h:42,
from /opt/local/include/gcc47/c++/bits/ios_base.h:43,
from /opt/local/include/gcc47/c++/ios:43,
from /opt/local/include/gcc47/c++/ostream:40,
from /opt/local/include/gcc47/c++/iostream:40,
from Driver.cpp:1:
/opt/local/include/gcc47/c++/bits/functional_hash.h: In instantiation of 'struct std::hash<Symbol>':
SeparateChaining.h:143:33: required from 'size_t HashTable<HashedObj>::myhash(const HashedObj&) const [with HashedObj = Symbol; size_t = long unsigned int]'
SeparateChaining.h:56:51: required from 'bool HashTable<HashedObj>::insert(HashedObj&) [with HashedObj = Symbol]'
Driver.cpp:135:26: required from here
/opt/local/include/gcc47/c++/bits/functional_hash.h:60:7: error: static assertion failed: std::hash is not specialized for this type
More specifically though.... The error:
error: static assertion failed: std::hash is not specialized for this type
Here is my Driver.cpp file:
#include <iostream>
#include <iomanip>
#include <cassert>
#include <fstream>
#include <string>
#include <vector>
#include <time.h>
#include <unistd.h>
#include <map>
#include <cstdlib>
#include <cmath>
#include "SeparateChaining.h"
using namespace std;
int TABLE_SIZE; //I know it's a global, but it allows the Table Size to be taken in within main() and used in hash()
size_t hash(const string & key);
class Symbol
{
private:
int key;
int type;
string data;
public:
const string & getData() const
{
return data;
}
int getType()
{
return type;
}
int getKey()
{
return labs(key);
}
void setType(int Type)
{
type = Type;
}
void setData(string Data)
{
data = Data;
}
void setKey(int Key)
{
key = Key;
}
bool operator== (const Symbol & rhs) const
{
return getData() == rhs.getData();
}
bool operator!= (const Symbol & rhs) const
{
return !(*this == rhs);
}
};
int main()
{
HashTable<Symbol> hashtable(TABLE_SIZE);
Symbol temp;
vector<Symbol> symbols;
string s;
int t;
int hash_key_array[TABLE_SIZE]; //array to hold hash key values
ifstream file;
file.open("symbols.txt");
if(!file)
{
cout << "System failed to open file.";
}
else
{
cout << "File successfully opened" << endl;
}
//for loop to read in the string name and the integer that follows the string name from symbols.txt
while(file >> s)
{
temp.setData(s);
file >> t;
temp.setType(t);
symbols.push_back(temp);
}
for(int i = 0; i < symbols.size(); i++)
{
cout << symbols[i].getData() << "\n";
cout << symbols[i].getType() << "\n";
}
cout << "What would you like the table size to be?" << endl;
cout << "Note: If the table size is greater than the number of objects" <<
" in the symbols.txt file, it will inevitably throw a segmentation fault" << endl;
cin >> TABLE_SIZE;
for(int j = 0; j < TABLE_SIZE; j++)
{
temp.setData(symbols[j].getData());
cout << temp.getData() << endl;
temp.setType(symbols[j].getType());
cout << temp.getType() << endl;
temp.setKey(::hash(symbols[j].getData()));
cout << "The key is: " << temp.getKey() << endl;
cout << endl;
hash_key_array[j] = temp.getKey();
for (int i = 0; i < TABLE_SIZE; i++)
{
if (i != j)
{
if (hash_key_array[i] == hash_key_array[j])
{
cout << endl;
cout << "Collision occurred at " << hash_key_array[i] << endl;
//rehash();
//cout << "The new key is: " << temp.getKey() << endl;
break;
}
}
}
hashtable.insert(temp);
}
}
size_t hash(const string & key)
{
size_t hashVal = 0;
for(char ch : key)
{
hashVal = 37 * hashVal + ch;
}
return labs(hashVal);
}
And my Header File.... SeperateChaining.h:
#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H
#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <functional>
//#include "Hash.h"
using namespace std;
// 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
int nextPrime( int n );
bool isPrime( int n );
template <typename HashedObj>
class HashTable
{
public:
//Uses the whatever value table_size has
//Otherwise, it will make a hash table of size 101
explicit HashTable( int TABLE_SIZE )
{
currentSize = 0;
theLists.resize(TABLE_SIZE);
}
bool contains( const HashedObj & x ) const
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//returns whatever you wanted to search for in the table provided it is there
return find( begin( whichList ), end( whichList ), x ) != end( whichList );
}
void makeEmpty( )
{
for( auto & thisList : theLists )
thisList.clear( );
}
bool insert(HashedObj & temp )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[myhash( temp )];
//goes through the beginning and end of the list, and if it
//doesn't get to the end, then it found the object you wanted to insert in the hash table already
//prevents duplicate insertions
if( find( begin( whichList ), end( whichList ), temp ) != end( whichList) )
return false;
//otherwise, it has gotten to the end of the list without finding a duplicate
//and puts what you want to insert in the list
whichList.push_back( temp );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool insert(const 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 )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//trying to find x within the list
//the iterator points to the slot in the list that contains x
auto itr = find( begin( whichList ), end( whichList ), x );
//if it gets to the end of the list without finding what you want to remove, then it returns false
if( itr == end( whichList ) )
{
return false;
}
//if it finds x, it removes it from the list
whichList.erase( itr );
--currentSize;
return true;
}
/*
void printTable()
{
for(int i=0; i < symbols.size(); i++)
{
cout << "The hash table contains: " << symbols[i] << endl;
}
}
*/
private:
vector<list<HashedObj>> theLists; // The array of Lists
int currentSize;
void rehash( )
{
vector<list<HashedObj>> oldLists = theLists;
// Creates new double-sized, empty table
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( auto & thisList : theLists )
thisList.clear( );
// Copies the old table into the new table
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;
return hf( x ) % theLists.size( );
}
};
int nextPrime( int n )
{
if( n % 2 == 0 )
{
++n;
}
for( ; !isPrime( n ); n += 2 )
{
}
return n;
}
bool isPrime( int n )
{
if( n == 2 || n == 3 )
return true;
if( n == 1 || n % 2 == 0 )
return false;
for( int i = 3; i * i <= n; i += 2 )
if( n % i == 0 )
return false;
return true;
}
#endif
I would really appreciate you guys helping me out!
You are doing this:
static hash<HashedObj> hf;
but you have not provided a hash template, or have not specialized std::hash for HashedObj.
You should avoid using namespace std;. Amongst other things, it is difficult to figure out which hash you want to get.

Inserting object into hash table... won't let me for some reason?

I'm designing a simple program that takes an object of the Symbol class which I have defined and inserts into a HashTable. I've been given the HashTable.h file which came from our textbook and as you'll see, it is designed to be able to handle any object.
I'm trying to insert my object via:
hashtable.insert(&temp) //where temp is the object
However, I'm getting these errors:
Driver.cpp: In function 'int main()':
Driver.cpp:127:27: error: no matching function for call to 'HashTable<Symbol>::insert(Symbol*)'
Driver.cpp:127:27: note: candidates are:
In file included from Driver.cpp:12:0:
SeperateChaining.h:50:10: note: bool HashTable<HashedObj>::insert(HashedObj&) [with HashedObj = Symbol]
SeperateChaining.h:50:10: note: no known conversion for argument 1 from 'Symbol*' to 'Symbol&'
SeperateChaining.h:72:10: note: bool HashTable<HashedObj>::insert(HashedObj&&) [with HashedObj = Symbol]
SeperateChaining.h:72:10: note: no known conversion for argument 1 from 'Symbol*' to 'Symbol&&'
Would you guys mind taking a look?
EDIT: When I try to insert by value as many of you suggested, I get back a ton of garbage but parsed out for errors there are two:
opt/local/include/gcc47/c++/bits/stl_algo.h:135:7: error: no match for 'operator==' in '__first.std::_List_iterator<_Tp>::operator*<Symbol>() == __val'
and
opt/local/include/gcc47/c++/bits/stl_algo.h:135:7: error: no match for 'operator==' in '__first.std::_List_iterator<_Tp>::operator*<Symbol>() == __val' –
Here's my driver file and hash table.h file:
Driver.cpp:
#include <iostream>
#include <iomanip>
#include <cassert>
#include <fstream>
#include <string>
#include <vector>
#include <time.h>
#include <unistd.h>
#include <map>
#include <cstdlib>
#include <cmath>
#include "SeperateChaining.h"
//#include "hash_chn.h"
using namespace std;
int TABLE_SIZE; //I know it's a global, but it allows the Table Size to be taken in within main() and used in hash()
size_t hash(const string & key);
class Symbol
{
private:
int key;
int type;
string data;
public:
const string & getData() const
{
return data;
}
int getType()
{
return type;
}
int getKey()
{
return labs(key);
}
void setType(int Type)
{
type = Type;
}
void setData(string Data)
{
data = Data;
}
void setKey(int Key)
{
key = Key;
}
};
int main()
{
HashTable<Symbol> hashtable(TABLE_SIZE);
Symbol temp;
vector<Symbol> symbols;
string s;
int t;
int hash_key_array[TABLE_SIZE]; //array to hold hash key values
ifstream file;
file.open("symbols.txt");
if(!file)
{
cout << "System failed to open file.";
}
else
{
cout << "File successfully opened" << endl;
}
//for loop to read in the string name and the integer that follows the string name from symbols.txt
while(file >> s)
{
temp.setData(s);
file >> t;
temp.setType(t);
symbols.push_back(temp);
}
for(int i = 0; i < symbols.size(); i++)
{
cout << symbols[i].getData() << "\n";
cout << symbols[i].getType() << "\n";
}
cout << "What would you like the table size to be?" << endl;
cout << "Note: If the table size is greater than the number of objects" <<
" in the symbols.txt file, it will inevitably throw a segmentation fault" << endl;
cin >> TABLE_SIZE;
for(int j = 0; j < TABLE_SIZE; j++)
{
temp.setData(symbols[j].getData());
cout << temp.getData() << endl;
temp.setType(symbols[j].getType());
cout << temp.getType() << endl;
temp.setKey(::hash(symbols[j].getData()));
cout << "The key is: " << temp.getKey() << endl;
cout << endl;
hash_key_array[j] = temp.getKey();
for (int i = 0; i < TABLE_SIZE; i++)
{
if (i != j)
{
if (hash_key_array[i] == hash_key_array[j])
{
cout << endl;
cout << "Collision occurred at " << hash_key_array[i] << endl;
//rehash();
//cout << "The new key is: " << temp.getKey() << endl;
break;
}
}
}
hashtable.insert(&temp); //problem is here
}
}
size_t hash(const string & key)
{
size_t hashVal = 0;
for(char ch : key)
{
hashVal = 37 * hashVal + ch;
}
return labs(hashVal);
}
SeperateChaining.h:
#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H
#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <functional>
//#include "Hash.h"
using namespace std;
// 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 HashTable
{
public:
//Uses the whatever value table_size has
//Otherwise, it will make a hash table of size 101
explicit HashTable( int TABLE_SIZE )
{
currentSize = 0;
theLists.resize(TABLE_SIZE);
}
bool contains( const HashedObj & x ) const
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//returns whatever you wanted to search for in the table provided it is there
return find( begin( whichList ), end( whichList ), x ) != end( whichList );
}
void makeEmpty( )
{
for( auto & thisList : theLists )
thisList.clear( );
}
bool insert(HashedObj & temp )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[myhash( temp )];
//goes through the beginning and end of the list, and if it
//doesn't get to the end, then it found the object you wanted to insert in the hash table already
//prevents duplicate insertions
if( find( begin( whichList ), end( whichList ), temp ) != end( whichList) )
return false;
//otherwise, it has gotten to the end of the list without finding a duplicate
//and puts what you want to insert in the list
whichList.push_back( temp );
// 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 )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//trying to find x within the list
//the iterator points to the slot in the list that contains x
auto itr = find( begin( whichList ), end( whichList ), x );
//if it gets to the end of the list without finding what you want to remove, then it returns false
if( itr == end( whichList ) )
{
return false;
}
//if it finds x, it removes it from the list
whichList.erase( itr );
--currentSize;
return true;
}
/*
void printTable()
{
for(int i=0; i < symbols.size(); i++)
{
cout << "The hash table contains: " << symbols[i] << endl;
}
}
*/
private:
vector<list<HashedObj>> theLists; // The array of Lists
int currentSize;
void rehash( )
{
vector<list<HashedObj>> oldLists = theLists;
// Creates new double-sized, empty table
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( auto & thisList : theLists )
thisList.clear( );
// Copies the old table into the new table
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;
return hf( x ) % theLists.size( );
}
};
#endif
hashtable.insert(&temp)
You have to insert by value, not by pointer. Remove the & operator.
hashtable.insert(&temp);
^
You are trying to insert an address of temp. This is what this error says:
note: bool HashTable::insert(HashedObj&) [with HashedObj =
Symbol] note: no known conversion for argument 1 from 'Symbol*' to
'Symbol&'
There is a version of insert that takes a reference as its argument. So instead of pointer insert the object by value:
hashtable.insert(temp);
Look at the errors you are getting:
SeperateChaining.h:50:10: note: bool HashTable<HashedObj>::insert(HashedObj&) [with HashedObj = Symbol]
SeperateChaining.h:50:10: note: no known conversion for argument 1 from 'Symbol*' to 'Symbol&'
SeperateChaining.h:72:10: note: bool HashTable<HashedObj>::insert(HashedObj&&) [with HashedObj = Symbol]
SeperateChaining.h:72:10: note: no known conversion for argument 1 from 'Symbol*' to 'Symbol&&'
This is telling you that you are calling insert with a Symbol* and the function insert takes either a Symbol& or a Symbol&&.
So, let's look at the code where you call insert:
hashtable.insert(&temp); //problem is here
Sure enough, you are using & which is the address-of operator which will take the address of temp, which is of type Symbol, returning a pointer to it (which is, of course, of type Symbol*). So you're calling the function with Symbol*, which is not what the functions expect.
Sidenote: your implementation has a few other issues that you will need to sort through. Ask yourself what is temp and what does the HashTable class do with the l- and r-value references to Symbol that it accepts?