Think-cell interview final.

This commit is contained in:
2014-12-24 12:44:39 +04:00
parent bc37faae71
commit fca912bbb4

View File

@@ -7,6 +7,7 @@ VIM: let g:argv=""
#include <map> #include <map>
#include <limits> #include <limits>
#include <iostream> #include <iostream>
#include <sstream>
// interval_map<K,V> is a data structure that efficiently associates intervals of keys of type K with values of type V. // interval_map<K,V> is a data structure that efficiently associates intervals of keys of type K with values of type V.
@@ -57,30 +58,54 @@ public:
if ( !(keyBegin < keyEnd ) ) if ( !(keyBegin < keyEnd ) )
return; return;
// //
// If there is a need to break the last interval with keyEnd do it. // - is bounded below, with the lowest value being std::numeric_limits<K>::min();
// Everything prior itEnd till itBegin will be removed. // std::numeric_limits<duble>::min() actually is not the smalles number.
//
if (keyBegin < std::numeric_limits<K>::min())
throw std::runtime_error("K should be bounded below, with the lowest value being std::numeric_limits<K>::min().");
//
// Find the interval pointer before which the new interval ends.
// //
auto ie = m_map.lower_bound(keyEnd); auto ie = m_map.lower_bound(keyEnd);
if ( ie != m_map.end() //
&& keyEnd < ie->first ) { // If there is a need to break the last interval with keyEnd do it now.
auto hint = ie--; // Everything prior 'ie' till 'ib' will be removed later.
ie = m_map.insert(hint,std::make_pair(keyEnd,ie->second)); //
if ( ie == m_map.end() && keyEnd < std::numeric_limits<K>::max()
|| ie != m_map.end() && keyEnd < ie->first ) {
if (!( std::prev(ie)->second == val ))
ie = m_map.insert(ie, std::make_pair(keyEnd,std::prev(ie)->second));
} }
// //
// There should always be std::numeric_limits<K>::min() // If the interval next to the inserting one should be joined?
//
else if (ie != m_map.end() && ie->second == val)
++ie;
//
// Find the interval pointer before which the new interval begins.
//
auto ib = m_map.lower_bound( keyBegin );
//
// If the interval before should be joined then ...
// Note: there should always be std::numeric_limits<K>::min()
//
if (ib != m_map.begin() && std::prev(ib)->second == val)
--ib;
//
// If keyBegin is less than 'ib' then insert an new interval.
//
else if ( ib == m_map.end() || keyBegin < ib->first )
ib = m_map.insert(ib, std::make_pair(keyBegin, val));
//
// Otherwise just change the value since keyBegin matches with an
// existing interval.
// //
auto it = --m_map.upper_bound( keyBegin );
if ( !(it->second == val ) )
{
if ( it->first < keyBegin )
it = m_map.insert(++it,std::make_pair(keyBegin,val));
else else
it->second = val; ib->second = val;
}
// //
// Find the range to be removed. // Removed the range between ib and ie.
// //
m_map.erase( ++it, ie ); m_map.erase( ++ib, ie );
} }
// look-up of the value associated with key // look-up of the value associated with key
@@ -150,12 +175,8 @@ void test_test_key() {
test_type b(T(5.5)); test_type b(T(5.5));
std::cout << "a<b before a=b: " << (a < b) << std::endl; std::cout << "a<b before a=b: " << (a < b) << std::endl;
a = b; a = b;
std::cout << "a<b after a=b: " << (a < b) << std::endl; std::cout << "a<b after a=b: " << (a < b) << std::endl;
// (a == b);
std::cout << "min: " << std::numeric_limits<test_type>::min() << std::endl; std::cout << "min: " << std::numeric_limits<test_type>::min() << std::endl;
std::cout << "max: " << std::numeric_limits<test_type>::max() << std::endl; std::cout << "max: " << std::numeric_limits<test_type>::max() << std::endl;
} }
@@ -185,22 +206,39 @@ void test_test_value() {
test_value<T> b(T(5.5)); test_value<T> b(T(5.5));
std::cout << "a==b before a=b: " << (a == b) << std::endl; std::cout << "a==b before a=b: " << (a == b) << std::endl;
a = b; a = b;
std::cout << "a==b after a=b: " << (a == b) << std::endl; std::cout << "a==b after a=b: " << (a == b) << std::endl;
// (a < b);
} }
template <typename T> template <typename T>
inline std::ostream& operator << ( std::ostream& os, test_value<T> t ) { inline std::ostream& operator << ( std::ostream& os, test_value<T> t ) {
return t.print(os); return t.print(os);
} }
//
// Test throws this exception if fails.
//
struct test_failed : public std::logic_error {
test_failed()
: logic_error("Test failed.")
{}
};
//
// The representation in m_map must be canonical, that is, consecutive map entries must not have the same value:
// ..., (0,'A'), (3,'A'), ... is not allowed.
//
template <class C>
void test_if_canonical(const C& c) {
for (auto it = std::next(c.begin()); it != c.end(); ++it) {
if (it->second == std::prev(it)->second)
throw test_failed();
}
}
// Provide a function IntervalMapTest() here that tests the functionality of the interval_map, // Provide a function IntervalMapTest() here that tests the functionality of the interval_map,
// for example using a map of unsigned int intervals to char. // for example using a map of unsigned int intervals to char.
// Many solutions we receive are incorrect. Consider using a randomized test to discover // Many solutions we receive are incorrect. Consider using a randomized test to discover
// the cases that your implementation does not handle correctly. // the cases that your implementation does not handle correctly.
void IntervalMapTest() { void IntervalMapTest() {
try {
#if 0 #if 0
std::cout << "=============================================" << std::endl; std::cout << "=============================================" << std::endl;
std::cout << "Test test_key<int>" << std::endl; std::cout << "Test test_key<int>" << std::endl;
@@ -219,21 +257,107 @@ void IntervalMapTest() {
test_test_value<double>(); test_test_value<double>();
#endif #endif
typedef test_key<double> key; // Check that key value is not less the std::numeric_limits<key>::min().
typedef test_value<double> val; try {
interval_map<test_key<double>, test_value<double>> im(0);
im.assign(0, 500, 3);
throw test_failed();
}
catch (const std::runtime_error&) {
}
//
// Check map for some interesting values.
//
typedef test_key<int> key;
typedef test_value<int> val;
interval_map<key, val> im(0); interval_map<key, val> im(0);
std::cout << "constrtuction: \n\t"; std::stringstream log;
im.print(std::cout); auto TEST = [&log,&im](const std::string& golden ) {
std::cout << std::endl; test_if_canonical(im.m_map);
std::stringstream ss;
im.print(ss);
log << ss.str() << std::endl;
if (ss.str() != golden)
throw test_failed();
};
// check initial state.
TEST("[-2147483648,0]");
im.assign(std::numeric_limits<key>::min(), std::numeric_limits<key>::min(), -1);
TEST("[-2147483648,0]");
im.assign(std::numeric_limits<key>::max(), std::numeric_limits<key>::max(), -1);
TEST("[-2147483648,0]");
im.assign(0, 0, -1);
TEST("[-2147483648,0]");
im.assign(std::numeric_limits<key>::min(), std::numeric_limits<key>::max(), -1);
TEST("[-2147483648,-1]");
im.assign(1000, 2000, 1); im.assign(1000, 2000, 1);
std::cout << "constrtuction: \n\t"; TEST("[-2147483648,-1][1000,1][2000,-1]");
im.print(std::cout);
std::cout << std::endl; im.assign(500, 1500, 1);
TEST("[-2147483648,-1][500,1][2000,-1]");
im.assign(1000, 1500, 2);
TEST("[-2147483648,-1][500,1][1000,2][1500,1][2000,-1]");
im.assign(0, 500, 3);
TEST("[-2147483648,-1][0,3][500,1][1000,2][1500,1][2000,-1]");
im.assign(-1000, -500, 3);
TEST("[-2147483648,-1][-1000,3][-500,-1][0,3][500,1][1000,2][1500,1][2000,-1]");
im.assign(-500, 0, 3);
TEST("[-2147483648,-1][-1000,3][500,1][1000,2][1500,1][2000,-1]");
im.assign(-500, 0, 4);
TEST("[-2147483648,-1][-1000,3][-500,4][0,3][500,1][1000,2][1500,1][2000,-1]");
im.assign(2000, std::numeric_limits<key>::max(), 4);
TEST("[-2147483648,-1][-1000,3][-500,4][0,3][500,1][1000,2][1500,1][2000,4]");
im.assign(3000, std::numeric_limits<key>::max(), 5);
TEST("[-2147483648,-1][-1000,3][-500,4][0,3][500,1][1000,2][1500,1][2000,4][3000,5]");
im.assign(2000, 3000, 5);
TEST("[-2147483648,-1][-1000,3][-500,4][0,3][500,1][1000,2][1500,1][2000,5]");
im.assign(std::numeric_limits<key>::min(), -1000, 4);
TEST("[-2147483648,4][-1000,3][-500,4][0,3][500,1][1000,2][1500,1][2000,5]");
im.assign(std::numeric_limits<key>::min(), -2000, 5);
TEST("[-2147483648,5][-2000,4][-1000,3][-500,4][0,3][500,1][1000,2][1500,1][2000,5]");
im.assign(-2000, -1000, 5);
TEST("[-2147483648,5][-1000,3][-500,4][0,3][500,1][1000,2][1500,1][2000,5]");
im.assign(-750, 1750, 4);
TEST("[-2147483648,5][-1000,3][-750,4][1750,1][2000,5]");
im.assign(-1000, 2000, 5);
TEST("[-2147483648,5]");
std::cout << log.str() << std::endl;
std::cout << "PASS" << std::endl;
} }
catch (const test_failed&) {
std::cerr << "FAIL: test_failed" << std::endl;
}
catch (const std::exception& e)
{
std::cerr << std::endl
<< "FAIL: std::exception(\"" << e.what() << "\")" << std::endl;
}
catch (...)
{
std::cerr << std::endl
<< "FAIL: unknown exception." << std::endl;
}}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
IntervalMapTest(); IntervalMapTest();