hashmap sparse

This commit is contained in:
hladu357 2024-05-17 13:43:06 +02:00
parent c2f021fbb3
commit 25db714aaa
1 changed files with 207 additions and 0 deletions

207
sparseMatrix.cpp Normal file
View File

@ -0,0 +1,207 @@
#ifndef __PROGTEST__
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <string>
#include <iostream>
#include <stdexcept>
#include <list>
#include <vector>
#include <algorithm>
using namespace std;
#endif /* __PROGTEST__ */
// https://fit-wiki.cz/%C5%A1kola/p%C5%99edm%C4%9Bty/bi-pa2/pa2_zkou%C5%A1ka_2023-06-01
template <typename T_>
class CSparseMatrix {
public:
// constructor
static constexpr size_t DEFAULT_TABLE_SIZE = 128;
static constexpr size_t DEFAULT_BUCKET_SIZE = 16;
CSparseMatrix( size_t x, size_t y )
: _x(x), _y(y), _m(DEFAULT_TABLE_SIZE), _l(0), _table(DEFAULT_TABLE_SIZE) {
}
// destructor, operator =, copy constructor if needed
CSparseMatrix( const CSparseMatrix& oth ) = default;
CSparseMatrix& operator=( const CSparseMatrix& oth ) = default;
//----------------------------------------------------------------------------
// operator ( row, col )
T_& operator()( size_t x, size_t y ) {
if (x >= _x || y >= _y) throw std::out_of_range("Index error");
if (_l > DEFAULT_BUCKET_SIZE) rehash();
std::vector< Record >& bucket = _table[ hash(x,y,_m)];
auto it = std::find_if(bucket.begin(), bucket.end(), [x, y](const Record& r){ return r._x == x && r._y == y; });
if (it == bucket.end()) {
bucket.emplace_back(x,y);
_l = std::max(_l, bucket.size());
return bucket.back()._data;
}
return it->_data;
}
//----------------------------------------------------------------------------
// contains ( row, col )
bool contains( size_t x, size_t y ) const {
if (x >= _x || y >= _y) return false;
const std::vector< Record >& bucket = _table[ hash(x,y,_m)];
auto it = std::find_if(bucket.begin(), bucket.end(), [x, y](const Record& r){ return r._x == x && r._y == y; });
return it != bucket.end();
}
//----------------------------------------------------------------------------
private:
struct Record {
size_t _x, _y;
T_ _data;
Record( size_t x, size_t y )
: _x(x), _y(y) {}
};
//----------------------------------------------------------------------------
static size_t hash( size_t x, size_t y, size_t m ) {
size_t tmp1 = (x * 4013) % 850973;
size_t tmp2 = (y * 7079) % 889271;
return (tmp1 ^ tmp2) % m;
}
//----------------------------------------------------------------------------
void rehash() {
std::vector< std::vector< Record > > newData(_m *= 2);
_l = 0;
for (auto& bucket : _table) {
for ( Record& r : bucket ) {
size_t newPos = hash(r._x, r._y, _m);
newData[ newPos ].emplace_back( r._x, r._y );
newData[ newPos ].back()._data = std::move(r._data);
_l = std::max( _l, newData[ newPos ].size() );
}
}
std::swap(_table, newData);
}
//----------------------------------------------------------------------------
size_t _x, _y, _m, _l;
std::vector< std::vector< Record > > _table;
};
#ifndef __PROGTEST__
int main ( void )
{
CSparseMatrix<int> m1 ( 300, 700 );
assert ( !m1 . contains ( 0, 0 ) );
m1 ( 0, 0 ) = 123;
m1 ( 1, 1 ) = 321;
m1 ( 2, 2 ) = m1 ( 1, 1 ) + m1 ( 0, 0 );
assert ( m1 . contains ( 0, 0 ) && m1 ( 0, 0 ) == 123 );
assert ( m1 . contains ( 1, 1 ) && m1 ( 1, 1 ) == 321 );
assert ( m1 . contains ( 2, 2 ) && m1 ( 2, 2 ) == 444 );
for ( int i = 0; i < 300; ++i )
for ( int j = 0; j < 300; ++j )
m1 ( i, j ) = i * j;
for ( int i = 0; i < 300; ++i )
for ( int j = 0; j < 300; ++j )
assert ( m1 . contains ( i, j ) && m1 ( i, j ) == i * j );
try
{
m1 ( 300, 300 ) = 666;
assert ( false );
}
catch ( out_of_range & o )
{
assert ( o . what() == "Index error"s );
}
catch ( ... )
{
assert ( false );
}
try
{
m1 ( 299, 300 ) = 322;
}
catch ( ... )
{
assert ( false );
}
CSparseMatrix m2 = m1;
for ( int i = 0; i < 300; ++i )
for ( int j = 0; j < 300; ++j )
assert ( m2 . contains( i, j ) && m2 ( i, j ) == i * j );
m1 ( 0, 0 ) = 15;
assert ( m2 ( 0, 0 ) == 0 );
assert ( m1 ( 0, 0 ) == 15 );
CSparseMatrix <int> m3 ( 1000, 1000 );
assert ( !m3 . contains ( 666, 666 ) );
m3 ( 666, 666 ) = 666;
assert ( m3 . contains ( 666, 666 ) && m3 ( 666, 666 ) == 666 );
m3 = m1;
assert ( !m3 . contains ( 666, 666 ) );
assert ( m3 . contains ( 0, 0 ) && m3 ( 0, 0 ) == 15 );
for ( int i = 1; i < 300; ++i )
for ( int j = 1; j < 300; ++j )
assert ( m3 . contains( i, j ) && m3 ( i, j ) == i * j );
CSparseMatrix <string> m4 ( 1000000, 1000000 );
assert ( !m4 . contains ( 0, 0 ) );
assert ( !m4 . contains ( 999999, 999999 ) );
m4 ( 0, 0 ) = "P";
m4 ( 10, 40 ) = "r";
m4 ( 55, 50000 ) = "o";
m4 ( 400000, 11 ) = "g";
m4 ( 999999, 1221 ) = "t";
m4 ( 121, 169 ) = "e";
m4 ( 66, 6 ) = "s";
m4 ( 6, 66 ) = "t";
assert ( m4 . contains ( 0, 0 ) && m4 ( 0, 0 ) == "P"s );
assert ( m4 . contains ( 10, 40 ) && m4 ( 10, 40 ) == "r"s );
assert ( m4 . contains ( 55, 50000 ) && m4 ( 55, 50000 ) == "o"s );
assert ( m4 . contains ( 400000, 11 ) && m4 ( 400000, 11 ) == "g"s );
assert ( m4 . contains ( 999999, 1221 ) && m4 ( 999999, 1221 ) == "t"s );
assert ( m4 . contains ( 121, 169 ) && m4 ( 121, 169 ) == "e"s );
assert ( m4 . contains ( 66, 6 ) && m4 ( 66, 6 ) == "s"s );
assert ( m4 . contains ( 6, 66 ) && m4 ( 6, 66 ) == "t"s );
std::cout << "success!\n";
return EXIT_SUCCESS;
}
#endif /* __PROGTEST__ */