Hello I want to build a graph for connecting sentences.
for example my files has following lines.
ab cd ef
ef gh ij
ij kl mn
xy ab cd
So I want each node should have one line i.e. ab cd ef should be one node and it should be connected to ef gh ij which should be connected to ij kl mn.
Basically last word of a line should be connect to any line whose first word matches with last word.
Here is what I have come up so far, but failing when I add Edges.
#include <map>
#include <string>
#include <deque>
#include <list>
#include <iostream>
#include <stack>
#include <fstream>
#include <vector>
class GraphNode {
public:
GraphNode(std::string name) {
std::vector<std::string> words;
std::string::size_type lastPos = name.find_first_not_of(' ', 0);
std::string::size_type pos = name.find_first_of(' ', lastPos);
while (std::string::npos != pos || std::string::npos != lastPos){
words.push_back(name.substr(lastPos, pos - lastPos));
lastPos = name.find_first_not_of(' ', pos);
pos = name.find_first_of(' ', lastPos);
}
first = words[0];
middle = " ";
for ( int i = 1; i < (int)words.size() - 1; i++) {
middle = words[i] + " ";
}
last = words[words.size() - 1 ];
}
~GraphNode() {};
std::string first;
std::string middle;
std::string last;
};
struct GraphNodeCompare {
bool operator() (const GraphNode& lhs, const GraphNode& rhs) {
return lhs.last < rhs.last;
}
};
class Graph {
public:
Graph() {}
~Graph() {}
typedef std::map <GraphNode, std::list<GraphNode>, GraphNodeCompare > GraphType;
void AddVertex ( GraphNode vertexID );
void AddEdge ( GraphNode vertexLeft, GraphNode vertexRight);
std::list<GraphNode> GetVertices(GraphNode vertexID);
friend std::ostream& operator << (std::ostream& os, const Graph& dt);
private:
GraphType m_graph;
protected:
};
void Graph::AddVertex(GraphNode vertexID) {
GraphType::const_iterator iter = m_graph.find(vertexID);
if ( iter == m_graph.end()) {
std::list<GraphNode> list;
m_graph[vertexID] = list;
}
}
void Graph::AddEdge( GraphNode vertexLeft, GraphNode vertexRight) {
AddVertex(vertexLeft);
AddVertex(vertexRight);
m_graph[vertexLeft].push_back(vertexRight);
m_graph[vertexRight].push_back(vertexLeft);
}
std::list<GraphNode> Graph::GetVertices(GraphNode vertexID) {
GraphType::const_iterator iter = m_graph.find(vertexID);
std::list<GraphNode> list;
if ( iter != m_graph.end()){
return m_graph[vertexID];
}
return list;
}
std::ostream& operator << (std::ostream& os, const Graph& graph) {
std::cout << "---------------------------------------------" << std::endl;
std::map<GraphNode, std::list<GraphNode>, GraphNodeCompare >::const_iterator iter;
for ( iter = graph.m_graph.begin(); iter != graph.m_graph.end(); ++iter) {
std::cout << iter->first.first << iter->first.middle << iter->first.last << " : " ;
std::list<GraphNode> list = iter->second;
std::list<GraphNode>::const_iterator iter1;
for ( iter1 = list.begin(); iter1 != list.end(); ++iter1) {
std::cout << iter1->first << iter1->middle << iter1->last << '\t' ;
}
std::cout << std::endl;
}
std::cout << "---------------------------------------------" << std::endl;
return os;
}
int main( int argc, char **argv) {
Graph *pGraph = new Graph();
std::ifstream dataFile("D:\\personal\\data\\datas3.txt");
if ( dataFile.peek() == EOF ) {
return -1;
}
if (dataFile.is_open()) {
while (! dataFile.eof() ) {
std::string line;
std::getline (dataFile,line);
GraphNode node(line);
pGraph->AddVertex(node);
std::list<GraphNode> vertices = pGraph->GetVertices(node);
for ( std::list<GraphNode>::iterator itr = vertices.begin(); itr != vertices.end(); ++itr) {
pGraph->AddEdge( node, *itr);
}
//std::cout << line << std::endl;
}
}
dataFile.close();
//std::cout << *pGraph;
delete pGraph;
}
I can suggest this tiny, non object-oriented implementation. Works fine for you problem:
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
typedef std::vector< std::string > Node;
typedef std::pair< int, int > Edge;
// Node stuff
std::string firstWord ( const Node& node ) { return *node.begin(); }
std::string lastWord ( const Node& node ) { return *node.rbegin(); }
void addWord ( Node& node, std::string s ) { node.push_back( s ); }
bool isNotEmpty( const Node& node ) { return !node.empty(); }
bool precedes( const Node& a, const Node& b ) { return lastWord( a ) == firstWord( b ); }
struct Graph
{
void addNode ( const Node& node ) { nodes.push_back( node ); }
void addEdge ( const int& from, const int& to ) { edges.push_back( Edge( from, to ) ); }
std::vector< Edge > edges;
std::vector< Node > nodes;
};
std::ostream& operator << ( std::ostream& out, const Graph& graph )
{
int esize = graph.edges.size();
for( int i = 0; i < esize; ++i )
{
int index1 = graph.edges[ i ].first, index2 = graph.edges[ i ].second;
for( int j = 0; j < graph.nodes[ index1 ].size(); ++j )
out << graph.nodes[ index1 ][ j ] << ' ';
out << "----> ";
for( int j = 0; j < graph.nodes[ index2 ].size(); ++j )
out << graph.nodes[ index2 ][ j ] << ' ';
out << std::endl;
}
return out;
}
int main ()
{
Graph graph;
std::ifstream inputFile( "input.txt" );
std::string s;
// reading from file and constructing graph vertices
if( inputFile.is_open() )
while( !inputFile.eof() )
{
std::getline( inputFile, s );
std::stringstream ss( s );
Node node;
while( ss >> s )
addWord( node, s );
if( isNotEmpty( node ) )
graph.addNode( node );
}
inputFile.close();
// constructing graph edges
std::vector< Node > nodes ( graph.nodes );
int sz = nodes.size();
for( int i = 0; i < sz; ++i )
for( int j = 0; j < sz; ++j )
if( precedes( nodes[ i ], nodes[ j ] ) )
graph.addEdge( i, j );
// let's see what we got
std::cout << graph;
return 0;
}
Also, as #spraff says, if you want to use a well-designed graph library, have a look at Boost.
Have you considered one of the excellent Boost libraries?
Related
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";
}
}
}
}
How can I split a string on multiple multi-character delimiters?
I want a function like vector<string> split_string(string input, vector<string> delims)
For example, split_string("foo+bar := baz",{"+"," ",":="}) = {"foo","+","bar"," "," ",":="," ","baz"}
My cut at the same. I chose to go with divide and conquer. It is not fast. It is not efficient. But it is simple.
Unfortunately it didn't work in this case because we are preserving the delimiters in the output. Dividing allowed later delimiters to split previously found delimiters.
Eg:
Source :=foo+bar . :=baz+quaax:= C++
Delims [+][ ][:=][:]
Result [:][=][foo][+][bar][ ][ ][.][ ][ ][ ][:][=][baz][+][quaax][:][=][ ][ ][C][+][+]
Yuck.
Finally settled on a similar approach to jafar's and added it to my support library to try out in a job I'm working on to replace the divide and conquer approach because it does look to be faster. Wouldn't have bothered posting this, but Jafar's is a bit over complicated for my tastes. Haven't done any profiling so his may be faster.
#include <iostream>
#include <vector>
// easy vector output
template<class TYPE>
std::ostream & operator<<(std::ostream & out,
const std::vector<TYPE> & in)
{
for (const TYPE &val: in)
{
out << "["<< val << "]";
}
return out;
}
// find the first of many string delimiters
size_t multifind(size_t start,
const std::string & source,
const std::vector<std::string> &delims,
size_t & delfound)
{
size_t lowest = std::string::npos;
for (size_t i = 0; i < delims.size(); i++)
{
size_t pos = source.find(delims[i], start);
if (pos == start)
{
lowest = pos;
delfound = i;
break;
}
else if (pos < lowest)
{
lowest = pos;
delfound = i;
}
}
return lowest;
}
// do the grunt work
std::vector<std::string> splitString(const std::string &source,
const std::vector<std::string> &delims)
{
std::vector<std::string> tokens;
size_t current = 0;
size_t delfound;
size_t next = multifind(current,
source,
delims,
delfound);
while(next != std::string::npos)
{
if (current < next)
{
tokens.push_back(source.substr(current, next - current));
}
tokens.push_back(delims[delfound]);
current = next + delims[delfound].length();
next = multifind(current,
source,
delims,
delfound);
}
if (current < source.length())
{
tokens.push_back(source.substr(current, std::string::npos));
}
return tokens;
}
void test(const std::string &source,
const std::vector<std::string> &delims)
{
std::cout << "Source " << source << std::endl;
std::cout << "Delims " << delims << std::endl;
std::cout << "Result " << splitString(source, delims) << std::endl << std::endl;
}
int main()
{
test(":=foo+bar . :=baz+quaax:= C++", { " ",":=","+" });
test(":=foo+bar . :=baz+quaax:= C++", { ":=","+"," " });
test(":=foo+bar . :=baz+quaax:= C++", { "+"," ",":=" });
test(":=foo+bar . :=baz+quaax:= C++", { "+"," ",":=",":" });
test(":=foo+bar . :=baz+quaax:= C++", { ":"," ",":=","+" });
test("foo+bar . :=baz+quaax:= C++lalala", { "+"," ",":=",":" });
}
Try this
#include <iostream>
#include <string>
#include <vector>
#include <map>
std::vector<std::string> splitString(std::string input, std::vector<std::string> delimeters);
std::string findFirstOf(std::string input, std::vector<std::string> del);
int main()
{
std::vector<std::string> words = splitString(":=foo+bar :=baz+quaax", { " ",":=","+" });
for (std::string str : words)
std::cout << str << ",";
std::cout << std::endl;
system("pause");
}
std::vector<std::string> splitString(std::string input, std::vector<std::string> delimeters)
{
std::vector<std::string> result;
size_t pos = 0;
std::string token;
std::string delimeter = findFirstOf(input, delimeters);
while(delimeter != "")
{
if ((pos = input.find(delimeter)) != std::string::npos)
{
token = input.substr(0, pos);
result.push_back(token);
result.push_back(delimeter);
input.erase(0, pos + delimeter.length());
}
delimeter = findFirstOf(input, delimeters);
}
result.push_back(input);
return result;
}
//find the first delimeter in the string
std::string findFirstOf(std::string input, std::vector<std::string> del)
{
//get a map of delimeter and position of delimeter
size_t pos;
std::map<std::string, size_t> m;
for (int i = 0; i < del.size(); i++)
{
pos = input.find(del[i]);
if (pos != std::string::npos)
m[del[i]] = pos;
}
//find the smallest position of all delimeters i.e, find the smallest value in the map
if (m.size() == 0)
return "";
size_t v = m.begin()->second;
std::string k = m.begin()->first;
for (auto it = m.begin(); it != m.end(); it++)
{
if (it->second < v)
{
v = it->second;
k = it->first;
}
}
return k;
}
output: ,:=,foo,+,bar, ,,:=,baz,+,quaax,.
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.
I'm attempting to create an algorithm in C++ which will give me all of the possible combinations of a set of list items (input in a map format). I want to avoid duplicates and make sure to cover all possible combinations. To simplify the example, here's what the input may look like:
map<string, vector<string> > sandwichMap;
sandwichMap["bread"].push_back("wheat");
sandwichMap["bread"].push_back("white");
sandwichMap["meat"].push_back("ham");
sandwichMap["meat"].push_back("turkey");
sandwichMap["meat"].push_back("roastbeef");
sandwichMap["veggie"].push_back("lettuce");
sandwichMap["sauce"].push_back("mustard");
I'd feed this map into the algorithm, and it should spit out a vector with all of the possible combinations (using one of each key type):
wheat+ham+lettuce+mustard
wheat+turkey+lettuce+mustard
wheat+roastbeef+lettuce+mustard
white+ham+lettuce+mustard
white+turkey+lettuce+mustard
white+roastbeef+lettuce+mustard
It needs to work for any map of string vectors. So far I've tried and gotten close, but I end up with duplicate combinations and missed combinations:
sandwichList getCombinations(sandwichMap sMap)
{
locList retList;
int totalCombos = 1;
for (sandwichMapIt i = sMap.begin(); i != sMap.end(); ++i)
{
totalCombos *= i->second.size();
}
retList.resize(totalCombos);
int locCount;
for (sandwichMapIt a = sMap.begin(); a != sMap.end(); ++a)
{
locCount = 0;
for (locListIt l = a->second.begin(); l != a->second.end(); ++l)
{
for (unsigned int i = 0; i < totalCombos / a->second.size(); ++i)
{
retList[i + a->second.size() * locCount] += *l;
}
locCount++;
}
}
return retList;
}
Any help would be greatly appreciated!
Updated code:
#include <vector>
#include <map>
#include <list>
#include <iostream>
typedef std::vector<std::string> strVec;
typedef std::list<std::string> strList;
typedef std::map<std::string, strVec> sandwichMap;
int main()
{
sandwichMap sMap;
sMap["bread"].push_back("wheat");
sMap["bread"].push_back("white");
sMap["meat"].push_back("ham");
sMap["meat"].push_back("turkey");
sMap["meat"].push_back("roastbeef");
sMap["veggie"].push_back("lettuce");
sMap["sauce"].push_back("mustard");
strList finalSandwichList;
for (sandwichMap::iterator i = sMap.begin(); i != sMap.end(); ++i)
{
strList tmpSandwich;
for (strVec::iterator j = i->second.begin(); j != i->second.end(); ++j)
{
if (finalSandwichList.empty())
{
tmpSandwich.push_back(*j);
}
else
{
for (strList::iterator k = finalSandwichList.begin(); k != finalSandwichList.end(); ++k)
tmpSandwich.push_back(*k + "+" + *j);
}
}
tmpSandwich.swap(finalSandwichList);
}
for (strList::iterator i = finalSandwichList.begin(); i != finalSandwichList.end(); ++i)
{
std::cout << *i << std::endl;
}
return 0;
}
//solution
std::list<std::string> result;
for(auto i=sandwichMap.begin(); i!=sandwichMap.end(); ++i) {
std::list<std::string> new_result;
for(auto j=i->second.begin(); j!=i->second.end(); ++j) {
if(result.empty())
new_result.push_back(*j);
else
for(auto k=result.begin(); k!=result.end(); ++k)
new_result.push_back(*k + "+" + *j);
}
new_result.swap(result);
}
This should work :
#include<iostream>
#include<map>
#include<string>
#include<algorithm>
using namespace std;
map<string, vector<string>> sMap;
vector<string> add;
int sett[200], countt;
void solve(map<string, vector<string>>::iterator itt, int ct, vector<string> addd){
vector<string> tmp = itt->second;
if(ct == countt){
for(int j=0;j<addd.size();j++){
cout<<addd[j]<<" ";
}
cout<<endl;
return;
}
itt++;
for(int i=0;i<tmp.size();i++){
//cout<<tmp[i]<<" ";
addd.push_back(tmp[i]);
solve(itt, ct+1, addd);
vector<string>::iterator tempIt = addd.end();
addd.erase(tempIt--);
}
}
int main(){
sMap["bre"].push_back("wh");
sMap["bre"].push_back("whi");
sMap["me"].push_back("ham");
sMap["me"].push_back("tur");
sMap["me"].push_back("rr");
sMap["veg"].push_back("let");
sMap["sau"].push_back("mus");
countt = sMap.size();
solve(sMap.begin(), 0, add);
return 0;
}
I have used backtracking to evaluate every possible combination.
Note : it is in c++11 you might need to change some part of the code for lower version of c++
link to output : http://ideone.com/Ou2411
The code is kinda long because of the helper methods, but it does the job:
#include <vector>
#include <string>
#include <map>
#include <iostream>
using namespace std;
template <class T>
vector<T> Head(const vector<T> &v) {
return vector<T>(v.begin(), v.begin() + 1);
}
template <class T>
vector<T> Tail(const vector<T> &v) {
auto first = v.begin() + 1;
auto last = v.end();
return vector<T>(first, last);
}
template <class T>
vector<T> Concat(const vector<T> &v1, const vector<T> &v2) {
vector<T> result = v1;
result.insert(result.end(), v2.begin(), v2.end());
return result;
}
vector<vector<string>> CombineVectorWithScalar(const vector<vector<string>> &v, const string &scalar) {
vector<vector<string>> result = v;
for (unsigned i = 0; i < v.size(); i++) {
result[i].push_back(scalar);
}
return result;
}
vector<vector<string>> CombineVectorWithVector(const vector<vector<string>> &v1, const vector<string> &v2) {
if (v2.empty()) {
return vector<vector<string>>();
}
else {
auto headCombination = CombineVectorWithScalar(v1, v2.front());
auto tailCombination = CombineVectorWithVector(v1, Tail(v2));
return Concat(headCombination, tailCombination);
}
}
vector<string> GetKeys(const map<string, vector<string>> &mp) {
vector<string> keys;
for (auto it = mp.begin(); it != mp.end(); ++it) {
keys.push_back(it->first);
}
return keys;
}
vector<vector<string>> CombineMapValues(const map<string, vector<string>> &mp) {
vector<string> keys = GetKeys(mp);
vector<vector<string>> result;
auto &firstVector = mp.begin()->second;
for (auto it = firstVector.begin(); it != firstVector.end(); ++it) {
vector<string> oneElementList;
oneElementList.push_back(*it);
result.push_back(oneElementList);
}
vector<string> restOfTheKeys = Tail(keys);
for (auto it = restOfTheKeys.begin(); it != restOfTheKeys.end(); ++it) {
auto ¤tVector = mp.find(*it)->second;
result = CombineVectorWithVector(result, currentVector);
}
return result;
}
void PrintCombinations(const vector<vector<string>> & allCombinations) {
for (auto it = allCombinations.begin(); it != allCombinations.end(); ++it) {
auto currentCombination = *it;
for (auto itInner = currentCombination.begin(); itInner != currentCombination.end(); ++itInner) {
cout << *itInner << " ";
}
cout << endl;
}
}
int main() {
map<string, vector<string> > sandwichMap;
sandwichMap["bread"].push_back("wheat");
sandwichMap["bread"].push_back("white");
sandwichMap["meat"].push_back("ham");
sandwichMap["meat"].push_back("turkey");
sandwichMap["meat"].push_back("roastbeef");
sandwichMap["veggie"].push_back("lettuce");
sandwichMap["sauce"].push_back("mustard");
auto allCombinations = CombineMapValues(sandwichMap);
PrintCombinations(allCombinations);
return 0;
}
void generate_all(std::map<std::string,std::vector<std::string>>::iterator start,
std::vector<std::string::iterator> accomulator,
std::map<std::string,std::vector<std::string>>& sMap){
for (auto it=start; it!=sMap.end(); ++it){
for (auto jt=it->second.begin(); jt!=it->second.end(); jt++){
generate_all(start+1,accomulator.pus_back[jt],sMap);
}
}
if (accomulator.size() == sMap.size()){
// print accomulator
}
}
Call with generate_all(sMap.begin(),aVector,sMap);
If the map is too big to go recursively, you can always generate an equivalent iterative code.
This solution is not recursive. Basically what it does is the following:
Compute how many combinations are actually possible
Know that for each key in the map, you're going to have to add nrCombinations/nrItemsInKey of them in total.
You can see it as a tree growing, branching more and more the more keys you have visited.
If you keep track of how many there are, how spaced they are and where they start you can automatically fill all combinations.
Code
#include <vector>
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, std::vector<std::string> > sandwichMap;
sandwichMap["bread"].push_back("wheat");
sandwichMap["bread"].push_back("white");
sandwichMap["meat"].push_back("ham");
sandwichMap["meat"].push_back("turkey");
sandwichMap["meat"].push_back("roastbeef");
sandwichMap["veggie"].push_back("lettuce");
sandwichMap["sauce"].push_back("mustard");
sandwichMap["sauce"].push_back("mayo");
// Compute just how many combinations there are
int combinationNr = 1;
for ( auto it : sandwichMap ) {
combinationNr *= it.second.size();
}
std::vector<std::vector<std::string>> solutions(combinationNr);
// We start with empty lists, thus we only have one cluster
int clusters = 1, clusterSize = combinationNr;
for ( auto category : sandwichMap ) {
int startIndex = 0;
int itemsNr = category.second.size();
int itemsPerCluster = clusterSize / itemsNr;
for ( auto item : category.second ) {
for ( int c = 0; c < clusters; ++c ) {
for ( int i = 0; i < itemsPerCluster; ++i ) {
// We sequentially fill each cluster with this item.
// Each fill starts offset by the quantity of items
// already added in the cluster.
solutions[startIndex+i+c*clusterSize].push_back(item);
}
}
startIndex += itemsPerCluster;
}
clusters *= itemsNr;
clusterSize = combinationNr / clusters;
}
for ( auto list : solutions ) {
for ( auto element : list ) {
std::cout << element << ", ";
}
std::cout << "\n";
}
return 0;
}
I posted earlier today and was able to work out a lot of my errors. However, I still have one error that I cannot figure out for the life of me. I'm basically just trying to insert a Symbol object into a HashTable and I'm constantly getting this message back:
In file included from /opt/local/include/gcc47/c++/bits/basic_string.h:3032:0,
from /opt/local/include/gcc47/c++/string:54,
from /opt/local/include/gcc47/c++/bits/locale_classes.h:42,
from /opt/local/include/gcc47/c++/bits/ios_base.h:43,
from /opt/local/include/gcc47/c++/ios:43,
from /opt/local/include/gcc47/c++/ostream:40,
from /opt/local/include/gcc47/c++/iostream:40,
from Driver.cpp:1:
/opt/local/include/gcc47/c++/bits/functional_hash.h: In instantiation of 'struct std::hash<Symbol>':
SeparateChaining.h:143:33: required from 'size_t HashTable<HashedObj>::myhash(const HashedObj&) const [with HashedObj = Symbol; size_t = long unsigned int]'
SeparateChaining.h:56:51: required from 'bool HashTable<HashedObj>::insert(HashedObj&) [with HashedObj = Symbol]'
Driver.cpp:135:26: required from here
/opt/local/include/gcc47/c++/bits/functional_hash.h:60:7: error: static assertion failed: std::hash is not specialized for this type
More specifically though.... The error:
error: static assertion failed: std::hash is not specialized for this type
Here is my Driver.cpp file:
#include <iostream>
#include <iomanip>
#include <cassert>
#include <fstream>
#include <string>
#include <vector>
#include <time.h>
#include <unistd.h>
#include <map>
#include <cstdlib>
#include <cmath>
#include "SeparateChaining.h"
using namespace std;
int TABLE_SIZE; //I know it's a global, but it allows the Table Size to be taken in within main() and used in hash()
size_t hash(const string & key);
class Symbol
{
private:
int key;
int type;
string data;
public:
const string & getData() const
{
return data;
}
int getType()
{
return type;
}
int getKey()
{
return labs(key);
}
void setType(int Type)
{
type = Type;
}
void setData(string Data)
{
data = Data;
}
void setKey(int Key)
{
key = Key;
}
bool operator== (const Symbol & rhs) const
{
return getData() == rhs.getData();
}
bool operator!= (const Symbol & rhs) const
{
return !(*this == rhs);
}
};
int main()
{
HashTable<Symbol> hashtable(TABLE_SIZE);
Symbol temp;
vector<Symbol> symbols;
string s;
int t;
int hash_key_array[TABLE_SIZE]; //array to hold hash key values
ifstream file;
file.open("symbols.txt");
if(!file)
{
cout << "System failed to open file.";
}
else
{
cout << "File successfully opened" << endl;
}
//for loop to read in the string name and the integer that follows the string name from symbols.txt
while(file >> s)
{
temp.setData(s);
file >> t;
temp.setType(t);
symbols.push_back(temp);
}
for(int i = 0; i < symbols.size(); i++)
{
cout << symbols[i].getData() << "\n";
cout << symbols[i].getType() << "\n";
}
cout << "What would you like the table size to be?" << endl;
cout << "Note: If the table size is greater than the number of objects" <<
" in the symbols.txt file, it will inevitably throw a segmentation fault" << endl;
cin >> TABLE_SIZE;
for(int j = 0; j < TABLE_SIZE; j++)
{
temp.setData(symbols[j].getData());
cout << temp.getData() << endl;
temp.setType(symbols[j].getType());
cout << temp.getType() << endl;
temp.setKey(::hash(symbols[j].getData()));
cout << "The key is: " << temp.getKey() << endl;
cout << endl;
hash_key_array[j] = temp.getKey();
for (int i = 0; i < TABLE_SIZE; i++)
{
if (i != j)
{
if (hash_key_array[i] == hash_key_array[j])
{
cout << endl;
cout << "Collision occurred at " << hash_key_array[i] << endl;
//rehash();
//cout << "The new key is: " << temp.getKey() << endl;
break;
}
}
}
hashtable.insert(temp);
}
}
size_t hash(const string & key)
{
size_t hashVal = 0;
for(char ch : key)
{
hashVal = 37 * hashVal + ch;
}
return labs(hashVal);
}
And my Header File.... SeperateChaining.h:
#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H
#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <functional>
//#include "Hash.h"
using namespace std;
// SeparateChaining Hash table class
//
// CONSTRUCTION: an approximate initial size or default of 101
//
// ******************PUBLIC OPERATIONS*********************
// bool insert( x ) --> Insert x
// bool remove( x ) --> Remove x
// bool contains( x ) --> Return true if x is present
// void makeEmpty( ) --> Remove all items
int nextPrime( int n );
bool isPrime( int n );
template <typename HashedObj>
class HashTable
{
public:
//Uses the whatever value table_size has
//Otherwise, it will make a hash table of size 101
explicit HashTable( int TABLE_SIZE )
{
currentSize = 0;
theLists.resize(TABLE_SIZE);
}
bool contains( const HashedObj & x ) const
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//returns whatever you wanted to search for in the table provided it is there
return find( begin( whichList ), end( whichList ), x ) != end( whichList );
}
void makeEmpty( )
{
for( auto & thisList : theLists )
thisList.clear( );
}
bool insert(HashedObj & temp )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[myhash( temp )];
//goes through the beginning and end of the list, and if it
//doesn't get to the end, then it found the object you wanted to insert in the hash table already
//prevents duplicate insertions
if( find( begin( whichList ), end( whichList ), temp ) != end( whichList) )
return false;
//otherwise, it has gotten to the end of the list without finding a duplicate
//and puts what you want to insert in the list
whichList.push_back( temp );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool insert(const HashedObj && x )
{
auto & whichList = theLists[ myhash( x ) ];
if( find( begin( whichList ), end( whichList ), x ) != end( whichList ) )
return false;
whichList.push_back( std::move( x ) );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool remove( const HashedObj & x )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//trying to find x within the list
//the iterator points to the slot in the list that contains x
auto itr = find( begin( whichList ), end( whichList ), x );
//if it gets to the end of the list without finding what you want to remove, then it returns false
if( itr == end( whichList ) )
{
return false;
}
//if it finds x, it removes it from the list
whichList.erase( itr );
--currentSize;
return true;
}
/*
void printTable()
{
for(int i=0; i < symbols.size(); i++)
{
cout << "The hash table contains: " << symbols[i] << endl;
}
}
*/
private:
vector<list<HashedObj>> theLists; // The array of Lists
int currentSize;
void rehash( )
{
vector<list<HashedObj>> oldLists = theLists;
// Creates new double-sized, empty table
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( auto & thisList : theLists )
thisList.clear( );
// Copies the old table into the new table
currentSize = 0;
for( auto & thisList : oldLists )
for( auto & x : thisList )
insert( std::move( x ) );
}
size_t myhash( const HashedObj & x ) const
{
static hash<HashedObj> hf;
return hf( x ) % theLists.size( );
}
};
int nextPrime( int n )
{
if( n % 2 == 0 )
{
++n;
}
for( ; !isPrime( n ); n += 2 )
{
}
return n;
}
bool isPrime( int n )
{
if( n == 2 || n == 3 )
return true;
if( n == 1 || n % 2 == 0 )
return false;
for( int i = 3; i * i <= n; i += 2 )
if( n % i == 0 )
return false;
return true;
}
#endif
I would really appreciate you guys helping me out!
You are doing this:
static hash<HashedObj> hf;
but you have not provided a hash template, or have not specialized std::hash for HashedObj.
You should avoid using namespace std;. Amongst other things, it is difficult to figure out which hash you want to get.