How to point to actual element not just the the array address? - c++

I have some like so:
struct Node{
int value;
Node *left, Node *right;
Node(): value(0), left(0), right(0){}
}
std::vector<Node> nodeList = getNodes();
I want the above to make a circular buffer. So
nodeList[i].left = &nodeList[i - 1];
nodeList[i].right= &nodeList[i + 1];
note that nodeList[0].left points to the end of the nodeList and nodeList.back().right points to the beginning on the nodeList;
Now here is the problem, nodeList[i].left and nodeList[i].right only points to the address of its previous neighbor, but does not necessarily point to the actual neighbor object. So if I were to sort the nodeList, the left and right pointer won't point to the original node anymore. Instead they will point to the new left and right neighbor. Hope the problem is clear, how can I have it so that for example nodeList[1].left points to nodeList[0] even if nodeList[0] got moved to a different spot?

You can just make a
std::vector<int> originalData = getOriginalData();
Then to sort it while preserving access to the original order, simply sort a
std::vector<int const*> itemPointers;
which you can initialize like this:
for( auto&& x : originalData )
{
itemPointers.push_back( &x );
}
Now just sort:
std::sort(
itemPointers.begin(), itemPointers.end(),
[]( int const* p1, int const* p2 ) { return (*p1 < *p2); }
);
Complete code showing also the details of accessing an original data predecessor item:
#include <algorithm> // std::sort
#include <iostream>
#include <utility> // std::begin, std:.end
#include <vector> // std::vector
//using namespace std;
std::vector< int > getOriginalData()
{
static int const data[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
return std::vector<int>( std::begin( data ), std::end( data ) );
}
int main()
{
std::vector<int> const originalData = getOriginalData();
std::vector<int const*> itemPointers;
for( auto const& x : originalData )
{
itemPointers.push_back( &x );
}
std::sort(
itemPointers.begin(), itemPointers.end(),
[]( int const* p1, int const* p2 ) { return (*p1 < *p2); }
);
std::wcout << "Sorted: ";
for( auto const p : itemPointers )
{
std::wcout << *p << " ";
}
std::wcout << std::endl;
std::wcout << "Predecessors in original data: ";
for( auto const p : itemPointers )
{
int const* const pPred = (p == &originalData[0]? nullptr : p - 1);
if( pPred == nullptr )
{ std::wcout << "! "; }
else
{ std::wcout << *pPred << " "; }
}
std::wcout << std::endl;
}

Related

How to find indexes of the n greatest elements

I have a container (Vector) of some arbitrary type and i want to get a vector with indices of the n greatest (or smallest) elements.
Is there a standard way to do so?
This is exactly the topic of one of the guru of the week http://www.gotw.ca/gotw/073.htm
I am reporting the preferred solution, however, I strongly recommend you to read the article (and the blog in general), it is really good.
#include <vector>
#include <map>
#include <algorithm>
namespace Solution3
{
template<class T>
struct CompareDeref
{
bool operator()( const T& a, const T& b ) const
{ return *a < *b; }
};
template<class T, class U>
struct Pair2nd
{
const U& operator()( const std::pair<T,U>& a ) const
{ return a.second; }
};
template<class IterIn, class IterOut>
void sort_idxtbl( IterIn first, IterIn last, IterOut out )
{
std::multimap<IterIn, int, CompareDeref<IterIn> > v;
for( int i=0; first != last; ++i, ++first )
v.insert( std::make_pair( first, i ) );
std::transform( v.begin(), v.end(), out,
Pair2nd<IterIn const,int>() );
}
}
#include <iostream>
int main()
{
int ai[10] = { 15,12,13,14,18,11,10,17,16,19 };
std::cout << "#################" << std::endl;
std::vector<int> aidxtbl( 10 );
// use another namespace name to test a different solution
Solution3::sort_idxtbl( ai, ai+10, aidxtbl.begin() );
for( int i=0; i<10; ++i )
std::cout << "i=" << i
<< ", aidxtbl[i]=" << aidxtbl[i]
<< ", ai[aidxtbl[i]]=" << ai[aidxtbl[i]]
<< std::endl;
std::cout << "#################" << std::endl;
}

how to access vector of map of ( int and vector of strings )

how do i access map of int and vectors of string in the passed_vector function.
I just want to print them in that function.
#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;
typedef vector< map< int, vector<string> > > vmis;
typedef map< int, vector<string> > mis;
typedef vector<string> vstr;
void passing_vector(const vmis &meetings);
//return size of vector
template< typename A > size_t n_elements( const A& a )
{
return sizeof a / sizeof a[ 0 ];
}
int main()
{
vmis meeting_info;
mis meeting_members;
vstr sw_vec;
vstr sys_vec;
string sw_team[] = {"Ricky", "John", "David"};
string sys_team[] = {"Simmon", "Brad", "Schmidt", "Fizio"};
sw_vec.insert(sw_vec.begin(), sw_team, sw_team + n_elements(sw_team) );
sys_vec.insert(sys_vec.begin(), sys_team, sys_team + n_elements(sys_team) );
meeting_members.insert(make_pair(520, sw_vec));
meeting_members.insert(make_pair(440, sys_vec));
meeting_info.push_back(meeting_members);
passing_vector(meeting_info);
return 0;
}
void passing_vector(const vmis &meetings)
{
vmis::iterator itvmis = meetings.begin();
//how do i access map of int and vectors of string.
//I just want to print them.
}
I know how to print them in main function.
vmis::iterator itvims = meeting_info.begin();
for( int i = 0; i < meeting_info.size(); i++ )
{
mis::iterator itm = meeting_members.begin();
for(itm; itm != meeting_members.end(); itm++ )
{
cout << itm->first << " : ";
vstr::iterator it = itm->second.begin();
for(it; it != itm->second.end(); it++)
cout << *it << " ";
cout << endl;
}
}
desired output
440 : Simmon Brad Schmidt Fizio
520 : Ricky John David
if there is a better way of doing this suggestions are always welcome.
The easiest aproach is to use auto, also since your meetings is const, you need to use const_iterator:
void passing_vector(const vmis &meetings)
{
vmis::const_iterator itvims = meetings.begin();
//how do i access map of int and vectors of string.
//I just want to print them.
for (;itvims != meetings.end(); ++itvims)
{
const auto& map_item = *itvims;
for (const auto& map_it : map_item)
{
int map_key = map_it.first;
const auto& str_vec = map_it.second;
for (const auto& str : str_vec)
{
std::cout << map_key << " - " << str << "\n";
}
}
}
}
[edit]
c++98 version:
void passing_vector(const vmis &meetings)
{
vmis::const_iterator itvims = meetings.begin();
//how do i access map of int and vectors of string.
//I just want to print them.
for (;itvims != meetings.end(); ++itvims)
{
const mis& map_item = *itvims;
for (mis::const_iterator map_it = map_item.begin(); map_it != map_item.end(); ++map_it)
{
int map_key = map_it->first;
const vstr& str_vec = map_it->second;
for (vstr::const_iterator sitr = str_vec.begin(); sitr != str_vec.end(); ++sitr)
{
std::cout << map_key << " - " << *sitr << "\n";
}
}
}
}

C++: read dataset and check if vector<Class> is subset of vector<Class>

I have the following piece of code. The code creates a vector Dataset, each element of which is a vector. It also creates a vector S.
I want to check which vector of Dataset contain vector of S. Apparently I am doing something wrong, because for the following example,
Dataset is:
a b c
a d
a b d
and S:
a b
it should print: 0 2
and for me it prints: 0 1 2
#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>
#include <string>
#include <time.h>
#include <vector>
#include <algorithm>
using namespace std;
class StringRef
{
private:
char const* begin_;
int size_;
public:
int size() const { return size_; }
char const* begin() const { return begin_; }
char const* end() const { return begin_ + size_; }
StringRef( char const* const begin, int const size )
: begin_( begin )
, size_( size )
{}
bool operator<(const StringRef& obj) const
{
return (strcmp(begin(),obj.begin()) > 0 );
}
};
/************************************************
* Checks if vector B is subset of vector A *
************************************************/
bool isSubset(std::vector<StringRef> A, std::vector<StringRef> B)
{
std::sort(A.begin(), A.end());
std::sort(B.begin(), B.end());
return std::includes(A.begin(), A.end(), B.begin(), B.end());
}
vector<StringRef> split3( string const& str, char delimiter = ' ' )
{
vector<StringRef> result;
enum State { inSpace, inToken };
State state = inSpace;
char const* pTokenBegin = 0; // Init to satisfy compiler.
for(auto it = str.begin(); it != str.end(); ++it )
{
State const newState = (*it == delimiter? inSpace : inToken);
if( newState != state )
{
switch( newState )
{
case inSpace:
result.push_back( StringRef( pTokenBegin, &*it - pTokenBegin ) );
break;
case inToken:
pTokenBegin = &*it;
}
}
state = newState;
}
if( state == inToken )
{
result.push_back( StringRef( pTokenBegin, &str.back() - pTokenBegin ) );
}
return result;
}
int main() {
vector<vector<StringRef> > Dataset;
vector<vector<StringRef> > S;
ifstream input("test.dat");
long count = 0;
int sec, lps;
time_t start = time(NULL);
cin.sync_with_stdio(false); //disable synchronous IO
for( string line; getline( input, line ); )
{
Dataset.push_back(split3( line ));
count++;
};
input.close();
input.clear();
input.open("subs.dat");
for( string line; getline( input, line ); )
{
S.push_back(split3( line ));
};
for ( std::vector<std::vector<StringRef> >::size_type i = 0; i < S.size(); i++ )
{
for(std::vector<std::vector<StringRef> >::size_type j=0; j<Dataset.size();j++)
{
if (isSubset(Dataset[j], S[i]))
{
cout << j << " ";
}
}
}
sec = (int) time(NULL) - start;
cerr << "C++ : Saw " << count << " lines in " << sec << " seconds." ;
if (sec > 0) {
lps = count / sec;
cerr << " Crunch speed: " << lps << endl;
} else
cerr << endl;
return 0;
}
Your StringRef type is dangerous because it contains a const char * pointer, but no concept of ownership. So the pointer could be invalidated at some point after the object is constructed.
And indeed this is what happens here: You have a single string (line) and create StringRefs with pointers to its internal data. When the string is later modified, these pointers are invalidated.
You should create a vector<std::string> instead to prevent this problem.

Structure to hold value by ranged key

I need a structure to hold a value based on a key that has a range.
My implementation is C++, so any STL or Boost would be excellent.
I have as range-key, which are doubles, and value
[0,2) -> value1
[2,5) -> value2
[5,10) -> value3
etc
Such that a search of 1.23 should return value1, and so on.
Right now I am using a vector containing all three parts, key1/key2/value, with custom searching, but it feels like there should be a cleaner structure.
Edit: Thanks all. Given the ranges in this case are supposed to be contiguous and non-overlapping, the use of upper_bound will work just fine. Thanks for the class Range solutions as well, they are filed away for future reference.
class Range
{
public:
Range( double a, double b ):
a_(a), b_(b){}
bool operator < ( const Range& rhs ) const
{
return a_ < rhs.a_ && b_ < rhs.b_;
}
private:
double a_;
double b_;
};
int main()
{
typedef std::map<Range, double> Ranges;
Ranges r;
r[ Range(0, 2) ] = 1;
r[ Range(2, 5) ] = 2;
r[ Range(5, 10) ] = 3;
Ranges::const_iterator it1 = r.find( Range( 2, 2 ) );
std::cout << it1->second;
Ranges::const_iterator it2 = r.find( Range( 2, 3 ) );
std::cout << it2->second;
Ranges::const_iterator it3 = r.find( Range( 6, 6 ) );
std::cout << it3->second;
return 0;
}
If your ranges are contiguous and non-overlapping, you should use std::map and the upper_bound member function. Or, you could use a sorted vector with the upper_bound algorithm. Either way, you only need to record the lowest value of the range, with the upper part of the range being defined by the next higher value.
Edit: I phrased that confusingly, so I decided to provide an example. In coding the example, I realized you need upper_bound instead of lower_bound. I always get those two confused.
typedef std::map<double, double> MyMap;
MyMap lookup;
lookup.insert(std::make_pair(0.0, dummy_value));
lookup.insert(std::make_pair(2.0, value1));
lookup.insert(std::make_pair(5.0, value2));
lookup.insert(std::make_pair(10.0, value3));
MyMap::iterator p = lookup.upper_bound(1.23);
if (p == lookup.begin() || p == lookup.end())
...; // out of bounds
assert(p->second == value1);
How about something along these lines:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <sstream>
class Range
{
public:
Range(double lower, double upper) : lower_(lower), upper_(upper) {};
Range(const Range& rhs) : lower_(rhs.lower_), upper_(rhs.upper_) {};
explicit Range(const double & point) : lower_(point), upper_(point) {};
Range& operator=(const Range& rhs)
{
lower_ = rhs.lower_;
upper_ = rhs.upper_;
return * this;
}
bool operator < (const Range& rhs) const
{
return upper_ <= rhs.lower_;
}
double lower_, upper_;
};
typedef std::string Thing;
typedef std::map<Range, Thing> Things;
std::string dump(const std::pair<Range,Thing> & p)
{
stringstream ss;
ss << "[" << p.first.lower_ << ", " << p.first.upper_ << ") = '" << p.second << "'" << endl;
return ss.str();
}
int main()
{
Things things;
things.insert( std::make_pair(Range(0.0, 5.0), "First") );
things.insert( std::make_pair(Range(5.0, 10.0), "Second") );
things.insert( std::make_pair(Range(10.0, 15.0), "Third") );
transform( things.begin(), things.end(), ostream_iterator<string> (cout,""), dump );
cout << "--------------------------------------" << endl;
things[Range(1.5)] = "Revised First";
transform( things.begin(), things.end(), ostream_iterator<string> (cout,""), dump );
return 0;
}
... program output:
[0, 5) = 'First'
[5, 10) = 'Second'
[10, 15) = 'Third'
--------------------------------------
[0, 5) = 'Revised First'
[5, 10) = 'Second'
[10, 15) = 'Third'

Does C++ have a sequential search function?

I have a small unsorted array and I'd like to find the index of a particular value. Does C++ have a built-in sequential search function for this, or do you just write the loop yourself each time it comes up?
I'm specifically using a C-style array like:
std::string arr[5] = { "EVEN", "ODD", "NONE", "MARK", "SPACE" };
and I need the index of a value that the user supplies.
Use std::find() from the STL-algorithm-library, or the find()-method of your particular container.
std::find() should work:
#include <stdio.h>
#include <algorithm>
#include <string>
using std::string;
std::string arr[5] = { "EVEN", "ODD", "NONE", "MARK", "SPACE" };
int main() {
string* pArrEnd = arr + sizeof( arr)/sizeof(arr[0]);
string* pFound = std::find( arr, pArrEnd, "MARK");
if (pFound == pArrEnd) {
printf( "not found\n");
}
else {
printf( "%s was found at index %d\n", pFound->c_str(), pFound - arr);
printf( "or using STL: %d\n", std::distance( arr, pFound));
}
return 0;
}
You can use STL algos on containers other than just STL containers. For example, you can std::find() in a C-style array:
// alloc the array
static const size_t numItems = 100000;
int * items = new int[numItems];
// fill the array
for( size_t n = 0; n < numItems; ++n )
items[n] = n;
// find 42 using std::find()
int* found = std::find(&items[0], &items[numItems], 42);
if( found == &items[numItems] )
{
// this is one past the end, so 42 was not found
items[0] = 42;
}
else
{
// we found the first instance of 42 at this location
// change it to 43
*found = 43;
}
I suppose you need the index and not the iterator.
int main()
{
// for c++ vector
typedef int Element;
typedef std::vector<Element> CppVector;
CppVector v;
v.push_back( 2 );
v.push_back( 4 );
v.push_back( 8 );
v.push_back( 6 );
const Element el = 4;
CppVector::const_iterator it = std::find( v.begin(), v.end(), el );
if ( it == v.end() )
{
std::cout << "there is no such element" << std::endl;
}
else
{
const CppVector::size_type index = it - v.begin();
std::cout << "index = " << index << std::endl;
}
// for C array
typedef Element CVector[4];
CVector cv;
cv[0] = 2;
cv[1] = 4;
cv[2] = 8;
cv[3] = 6;
const std::size_t cvSize = sizeof( cv ) / sizeof( Element );
std::cout << "c vector size = " << cvSize << std::endl;
const Element* cit = std::find( cv, cv + cvSize, el );
const std::size_t index = cit - cv;
if ( index >= cvSize )
std::cout << "there is no such element" << std::endl;
else
std::cout << "index = " << index << std::endl;
}
In addition to the STL possibility (std::find) already mentioned there is the POSIX function lsearch (with c semantics).