From 25db714aaac16d4feb4f6b7974a08e8687e9cd94 Mon Sep 17 00:00:00 2001 From: hladu357 Date: Fri, 17 May 2024 13:43:06 +0200 Subject: [PATCH] hashmap sparse --- sparseMatrix.cpp | 207 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 sparseMatrix.cpp diff --git a/sparseMatrix.cpp b/sparseMatrix.cpp new file mode 100644 index 0000000..73e6c6d --- /dev/null +++ b/sparseMatrix.cpp @@ -0,0 +1,207 @@ +#ifndef __PROGTEST__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +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 +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 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 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 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__ */ \ No newline at end of file