Does C++ have a sequential search function? - c++

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).

Related

How to avoid repetitions when comparing two vectors by blocks

I am trying to compare two vectors which are of size of multiple of 4 and data is represented in terms of blocks (4 elements). Each vector block has a unique number it e.g {0,0,0,0}, {0,0,0,1}, {0,0,0,2} or {0,0,0,0,0,0,0,1,0,0,0,2} and {0,0,0,2,0,0,0,1} so on. I am using iterator which increments i+=4 every time. I wrote a small function which do the job but the blocks tend to repeat. I am not sure how t0 remove repetition of these block. e.g vector_A {0,0,0,0,0,0,0,1} vector_B {0,0,0,1,0,0,0,0,0,0,0,2} it should give local_vector1 {0,0,0,2} instead I get local vector_1 {0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,2}
void comparing_vectors_by_block(std::vector<int> vector_A, std::vector<int>
vector_B)
{
const int blockSize = 4;
std::vector<int> local_vector1;
std::cout << "size of the vector_A: " << vector_A.size() << std::endl;
std::cout << "size of the vector_B: " << vector_B.size() << std::endl;
for (auto it_A = std::begin(vector_A); it_A != std::end(vector_A); it_A+=4)
{
for (auto it_B = std::begin(vector_B); it_B != std::end(vector_B); it_B += 4)
{
bool match = equal(it_A, it_A + blockSize, it_B, it_B + blockSize);
if (!match)
{
std::cout << "match :" << std::endl;
local_vector1.insert(local_vector1.end(), it_B, it_B + blockSize);
}
else
{
std::cout << "not matched :" << std::endl;
}
}
}
Use a vector of arrays of four ints to represent the data.
std::vector<std::array<int,4>> vect1;
If this data has some other meaning. It is better to use the OOP way and create
a struct or a class to represent that four numbers data. Then implement operator == and other helpful methods for the struct/class.
struct foo{
int a;
int b;
int c;
ind d;
};
bool foo::operator==(const X& lhs, const X& rhs){ /* do actual comparison */ }
Then just iterate the vector and compare the elements using == like you would do if the vector was of type int for example.
for(auto& x : vector_A)
{
if(std::find(vector_B.begin(), vector_B.end(), x) != vector_B.end()) {
local_vector1.append(x);
}
}
If I got you right, you want to get the symmetric difference of two vectors of blocks. I.e. for A = {0,0,0,3,0,0,0,0,0,0,0,1} and B = {0,0,0,1,0,0,0,0,0,0,0,2} you want to have local_vector1 = {0,0,0,3,0,0,0,2}.
In your implementation you compare each block of vector A with each block of vector B -- of course, you'll get extra mismatches. My (also non-optimized) solution:
std::vector<int> get_blocked_vectors_diff( const std::vector<int>& vector_A, const std::vector<int>& vector_B )
{
const int blockSize = 4;
std::vector<int> local_vector;
for ( auto it_A = std::begin( vector_A ); it_A != std::end( vector_A ); it_A += 4 )
{
bool found_in_B = false;
for ( auto it_B = std::begin( vector_B ); !found_in_B && it_B != std::end( vector_B ); it_B += 4 )
{
found_in_B = std::equal( it_A, it_A + blockSize, it_B, it_B + blockSize );
}
if ( !found_in_B )
{
local_vector.insert( local_vector.end( ), it_A, it_A + blockSize );
}
}
return local_vector;
}
void comparing_vectors_by_block(std::vector<int> vector_A, std::vector<int> vector_B)
{
auto A_mines_B = get_blocked_vectors_diff( vector_A, vector_B );
auto B_mines_A = get_blocked_vectors_diff( vector_B, vector_A );
auto local_vector1( A_mines_B );
local_vector1.insert( local_vector1.end(), B_mines_A.begin( ), B_mines_A.end( ) );
for ( auto a : local_vector1 )
{
std::cout << a << " ";
}
std::cout << std::endl;
}
Note, that we need two parts of the answer: A\B and B\A, so get_blocked_vectors_diff is called twice.
If you change your data structure like Petar Velev suggested, you will be able to shorten get_blocked_vectors_diff function:
std::vector<int> get_blocked_vectors_diff( const std::vector<Block>& vector_A, const std::vector<Block>& vector_B )
{
std::vector<Block> local_vector;
for ( auto& x : vector_A )
{
if ( std::find( vector_B.begin( ), vector_B.end( ), x ) == vector_B.end( ) )
{
local_vector.push_back( x );
}
}
return local_vector;
}
Better solutions could be obtained if you sort your vectors of blocks first.

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.

Iterate elements of array using pointer

I try execute code:
char* m[3] = {"123", "456", "789"};
for(char* st=*m; st!=0; st=*(m+1))
{
cout <<st;
}
but it hung up and print: 123456456456...
The loop you wrote is invalid
char* m[3]={"123","456","789"};
for(char* st=*m;st!=0; st=*(m+1))
{
cout <<st;
}
Expression *m has type char * and array m does not contain NULL pointer. So condition st!=0;
is wrong. And the pointer always will point the same element because expression st=*(m+1) gives always the second element of the array
Also take into account that the correct definition of the array will be
const char* m[3] = { "123", "456", "789" };
because it is an array of pointers to string literals and string literals may not be changed.
You could use simply the range based for statement
const char* m[3] = { "123", "456", "789" };
for ( const char* st : m )
{
cout <<st << std::endl;
}
Or you could use iterators in the loop. For example
const char* m[3] = { "123", "456", "789" };
for ( auto it = std::begin( m ); it != std::end( m ); ++it )
{
cout << *it << std::endl;
}
And you could use standard algorithm std::copy
#include <iostream>
#include <algorithm>
#include <iterator>
//,,,
const char* m[3] = { "123", "456", "789" };
std::copy( std::begin( m ), std::end( m ),
std::ostream_iterator<const char *>( std::cout, "\n" ) );
Stop using char* for strings immediately and start using std::string. The same goes for C-style arrays: start using std::array or std::vector. This will save you years of your life and unnecessary pain.
Just look at how beautiful this code is:
std::array<std::string, 3> m = {"123", "456", "789"};
for (auto& s : m)
std::cout << s;
and here's the live example.
Using the code you provided here is one way of doing it:
const char* m[3]={"123","456","789"};
const unsigned int element_count = sizeof(m) / sizeof(m[0]);
//not a nice to have sizeof here, but i used this to keep the code
// consistent with the code provided in the question
for( const char** st = m; st!= (m + element_count) ; st ++ )
{
cout << *st;
}
As you can see to iterate trough an array of char* elements you need to use a pointer to char* and therefore the type is char ** for the iteration variable st.
The code you has was an infinite loop because you assigned st with *(m+1) which is never equal to 0, in fact it's the second element every time.
However there are safer ways of using doing this, by using a std::vector for example:
std::vector<std::string> m = {"123", "456", "789"};
for (auto& st : m)
std::cout << st;
//or:
for(std::vector<std::string>::iterator i = m.begin(),e = m.end();i != e;i++)
std::cout << *i;
//or:
for(std::size_t i = 0;i < m.size() ;i++)
std::cout << m[i];
The problem is that you point a pointer to the same location in each iteration:
char* m[ 3]={ "123","456","789"};
for( char* st = *m; st != 0; st = *( m + 1))
// ^^^^^^^^^ <- this doesn't change,
// st points to *(m+1)
{
std::cout << st;
}
Also you should not use a non-const char * to point to a nonmodifiable string literal:
const char* m[ 3]={ "123","456","789"};
const unsigned int n = sizeof( m) / sizeof( m[ 0]);
for( const char** st = m; st != (m + n) ; st ++ )
{
cout << *st;
}
Even range - based iteration will work:
const char* m[ 3] = { "123", "456", "789" };
for ( const char* st : m )
{
std::cout << st << std::endl;
}
If for some reason you have to stick to simple iteration, this will also work:
const char* m[ 3]={ "123","456","789"};
const char* st;
int r = 0;
for( st = *m; r < 3; st = *( m+r))
{
std::cout << st << std::endl;
r++;
}
Please consider using a standard container, i.e std::vector or std::array. It will help you a lot, mainly in dynamic memory management.
std::vector< std::string> v = { "123", "456", "789"};
for ( auto& s : v)
std::cout << s;
This is the least intrusive solution:
char* m[4] = {"123", "456", "789", NULL};
for(char** st=m; *st!=0; st=(st+1))
{
cout <<*st;
}

How to point to actual element not just the the array address?

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;
}