#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__ */