I'm trying to use Dynamic Programming to implement fibonacci. Here's my .h file:
#ifndef DYNAMICPROGRAMMING_H
#define DYNAMICPROGRAMMING_H
#include <map>
class DynamicProgramming
{
public:
DynamicProgramming ();
~DynamicProgramming ();
int Fibonacci(int value);
private:
};
#endif // DYNAMICPROGRAMMING_H
Here's the relevant part in my .cpp file:
int DynamicProgramming::Fibonacci(int value)
{
int result;
std::map<int,int>fibonacci_storage;
std::map<int,int>::iterator valueFinder;
if (value == valueFinder->second){
return fibonacci_storage[value];
}
if (value <= 2 ){
result = 1;
} else {
result = Fibonacci(value - 1) + Fibonacci(value - 2);
}
fibonacci_storage.insert(std::pair<int,int>(value,result));
return result;
}
My error is coming from this line: if (value == valueFinder->second). This is what it says:
could not convert '((DynamicProgramming*)this)->DynamicProgramming::fibonacci_storage.std::map<_Key, _Tp, _Compare, _Alloc>::find [with _Key = int, _Tp = int, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, int> >, std::map<_Key, _Tp, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const int, int> >, std::map<_Key, _Tp, _Compare, _Alloc>::key_type = int]((*(const key_type*)(& value)))' from 'std::map<int, int>::iterator {aka std::_Rb_tree_iterator<std::pair<const int, int> >}' to 'bool'
It looks to me like this is a very simple error, but I'm not sure what all that stuff means. Can someone help me out, I'd really like to master this language, it seems like it would be very useful.
To check if a key exists in a C++ map, you can use std::map::count. It returns 0 (the key is absent) or 1 (the key is present).
To check if a value exists in a C++ map, I think that you have to iterate over all pairs.
It seems that your question is more about a compilation error though.
There are several issues in the code above.
Your iterator valueFinder is not iterating over anything. To iterate, you need to call the begin() method on a map.
The variable fibonacci_storage is basically useless because it is not a member of the object and thus there is a different instance of that variable for each call to the Fibonacci method.
Technically, you don't have to iterate because the indices of your Fibonacci sequence are the keys in the map, and the values of your Fibonacci sequence are the values in your map.
As far as I know the only way to search through maps values is to iterate through. If you are trying to see if the key exists then you can use
map.find()
There are several issues with your code.
The biggest one is not syntax, it's the placement of the cache: since fibonacci_storage is a local variable, each recursive invocation of Fibonacci will have its own cache, meaning that there would be no caching at all. You need to move fibonacci_storage into the private: section of your class.
As far as fixing the syntax goes, a common trick used to implement searching of cache is to store the result of [] in a reference, like this:
int DynamicProgramming::Fibonacci(int value)
{
int &result = fibonacci_storage[value];
if (result) {
return result;
}
if (value <= 2 ){
return (result = 1);
}
return (result = Fibonacci(value - 1) + Fibonacci(value - 2));
}
Variable result holds a reference to the value inside the map, so when you update it in one of the two assign-return statements the corresponding value inside the map gets updated automatically.
Demo.
valueFinder is just an iterator for the type std::map<int,int> that is not associated to any instance of that type.
To associate it to an instance (here fibonacci_storage) you have to assign it to that instance, i.e.
valueFinder = fibonacci_storage.begin();
Finding an element can be done with source
valueFinder = fibonacci_storage.find(value);
where value is the key you are searching for. Now you check if value is in the map:
if( valueFinder != fibonacci_storage.end() )
{
// value found
}
and you're done.
Related
I'm familiar with Python's dictionary function, and I'm assuming based on my research that C++'s map function is relatively similar. However I'm running into a "conversion" issue:
std::string dictionary(std::string inquiry){
std::map<std::string, std::string> mapK;
mapK["12th st. Oakland City Center"]="12th";
mapK["16th st. Mission"]="16th";
return mapK.find(inquiry);
}
This is a string function that should receive a string and then with the corresponding key return a string back to the main. Evidently there's an issue with the return statement.
error: could not convert 'mapK.std::map<_Key, _Tp, _Compare, _Alloc>::find<std::basic_string<char>, std::basic_string<char>, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, std::basic_string<char> > > >((*(const key_type*)(& inquiry)))' from 'std::map<std::basic_string<char>, std::basic_string<char> >::iterator {aka std::_Rb_tree_iterator<std::pair<const std::basic_string<char>, std::basic_string<char> > >}' to 'std::string {aka std::basic_string<char>}'
return mapK.find(inquiry);
std::map::find() returns iterator, specifically std::map::iterator.
The only thing you need to fix is to put a dereference:
return *mapK.find(inquiry);
Or even better, just use operator[]:
return mapK[inquiry];
Do note though that if inquiry is not in the map, it will return empty string. In case of find, it is straight undefined behavior.
Your problem is with the return type of find. It does not return the mapped type. Rather it returns an iterator.
The signature for find is iterator find( const Key& key ); (see here; there is also the const overload).
You should also check whether the key was found. So you could write something like
MapType::iterator i = mapK.find(inquiry);
if (i != mapK.end())
return i->second;
else
return ""; // or handle error some other way
Alternatively you could use the member access operator[], but this will insert a default constructed element in the map if the key is not found.
I am trying to learn C++ by converting some programs I wrote in java. One is an encryption program that takes text input and makes it look like DNA ( AGCTGTGCT... ). I can encrypt 64 characters using 256 codons of 4 bases each. ( "A" = "TGGC", "B" = "ATGC"...) In java, I make a hashmap<String, String[]> where the key is the character to be encrypted and the value is an array of 4 strings, where each string is a codon that is chosen at random to replace the encrypted character.
In C++ I am trying to use a map to do the same thing, but it gives an error I just don't understand. Here is the code where I try to make the codon table:
// iterate through the characters and select 4 codons from the list
for(int i = 0; i < 64; i++){
codonTable[charList[i]][0] = originalCodonList[4 * i];
codonTable[charList[i]][1] = originalCodonList[4 * i + 1];
codonTable[charList[i]][2] = originalCodonList[4 * i + 2];
codonTable[charList[i]][3] = originalCodonList[4 * i + 3];
}
}
charList is the array that holds the 64 encodable characters ( they are really strings ) and originalCodonList is a string array that contains the 256 codons. I've tried several ways to assign 4 codons to the string array in the map, but nothing really seems to work. This generates the least error spam. Here is the output when I compile it:
In file included from /usr/include/c++/4.6/map:61:0,
from Genencrypt.cpp:4:
/usr/include/c++/4.6/bits/stl_map.h: In member function ‘std::map<_Key, _Tp, _Compare, >_Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) >[with _Key = std::basic_string, _Tp = std::basic_string [4], _Compare = >std::less >, _Alloc = std::allocatorstd::basic_string, std::basic_string [4]> >, std::map<_Key, _Tp, _Compare, >_Alloc>::mapped_type = std::basic_string [4], std::map<_Key, _Tp, _Compare, >_Alloc>::key_type = std::basic_string]’:
Genencrypt.cpp:63:25: instantiated from here
/usr/include/c++/4.6/bits/stl_map.h:453:11: error: conversion from ‘int’ to non-scalar type >‘std::map, std::basic_string [4]>::mapped_type {aka >std::basic_string [4]}’ requested
Of course google tells me it's too long when I copy it into google. I'm not an expert in java, and I am much much better at java than at c++.
TL;DR: I want to make a map<string, string[]> in c++, is it possible and how to do it?
EDIT: Here is how I fixed it, I changed codonList from map<string. string[]> to map<string, vector<string> > and used this code to add the codons
for(int i = 0; i < 64; i++){
codonTable[charList[i]].push_back(originalCodonList[4 * i]);
codonTable[charList[i]].push_back(originalCodonList[4 * i + 1]);
codonTable[charList[i]].push_back(originalCodonList[4 * i + 2]);
codonTable[charList[i]].push_back(originalCodonList[4 * i + 3]);
std::cout << "Working?" << std::endl;
}
The problem is that you cannot use C-style arrays in standard library containers, because they do not meet certain requirements such as being assignable and copy constructible. However, you can use the std::array container if you know the size of the array at compile time, or an std::vector if not:
#include <map>
#include <array>
#include <vector>
std::map<std::string, std::array<std::string, 4>> m_fixed;
std::map<std::string, std::vector<std::string>> m_dynamic;
Note that std::array is part of C++11. If you don't have C++11 support, you may use the TR1 version std::tr1::array from the <tr1/array> header, or the Boost library version.
In C++ what you're trying to accomplish can be done with a std::map<std::string, std::vector<std::string> >.
Alternatively, since you're really just associating multiple string values with a single string key, you could use std::multimap<std::string, std::string>.
Also note that if you don't care about being able to iterate through keys in order, std::unordered_multimap<std::string, std::string> may be preferable (you normally expect constant complexity instead of logarithmic).
You're actaully looking for another class. C++ has std::multimap<Key, Value>. Unlike a regular map, multimap allows multiple values per key. In your case, you can store 4 string values per string key.
#include "UserUserSim.h"
UserUserSim::UserUserSim(string &query_url):
_query_url(query_url)
{
}
void UserUserSim::calculate(){
ifstream infile(_query_url.c_str());
string line;
while(infile){
int movie_id;
int user_id;
infile>>line;
if (line[line.length()-1]==':'){
movie_id=atoi(line.c_str());
cout<<line<<endl;
}
else{
user_id=atoi(line.c_str());
if (_set.find(user_id)==_set.end())
getTop(user_id);
float score=getScore(user_id,movie_id);
cout<<score<<endl;
}
}
}
float UserUserSim::getScore(int &user_id, int &movie_id){
vector<USim>* p=_map[user_id];
MovieList* ml=MovieDictionary::getInstance().getMovie(movie_id);
ml->sortList();
vector<UserScore>::iterator it;
vector<USim>::iterator sim_it=p->begin();
float score=0;
float total_weight=0;
for (it=ml->begin();it<ml->end();it++){
while ((*it).user_id>(*sim_it).user_id){ // the user did not rate in ths movie
sim_it++;
}
if ((*it).user_id==(*sim_it).user_id){
score+=(*sim_it).score * (*it).rating; // score of similarity * rating
total_weight+=(*sim_it).score;
sim_it++; // move on to the next user
}
}
score=score/total_weight;
return score;
}
typedef pair<int, float> mapPair;
bool compareSim(mapPair p1, mapPair p2){
return p1.second>p2.second;
}
bool compareID(mapPair p1, mapPair p2){
return p1.first<p2.first;
}
void UserUserSim::getTop(int &user_id){
vector<USim> list;
vector<USim>* p=&list;
_map.insert(pair<int,vector<USim>*>(user_id,p));
_set.insert(user_id);
UserList* ul=UserDictionary::getInstance().getUser(user_id);
map<int,float> user_score_map;
vector<MovieScore>::iterator it;
vector<UserScore>::iterator it_movie; // the iterator for the movielist
for (it=ul->begin();it<ul->end();it++){ // for each movie rating in the Vector
int movie_id=(*it).movie_id;
MovieList* ml=MovieDictionary::getInstance().getMovie(movie_id);
for(it_movie=ml->begin();it_movie<ml->end();it_movie++){
int user_id=(*it_movie).user_id;
if (user_score_map.find(user_id)==user_score_map.end()){
user_score_map.insert(pair<int,float>(user_id,0));
}else{
user_score_map[user_id]+=(*it).rating*(*it_movie).rating;// the vector's user rating x the rating of the movie,user
}
}
}
//vector< pair<int,float> > user_score_v;
map<int,float>::iterator it_map;
for (it_map=user_score_map.begin();it_map<user_score_map.end();it_map++){} //<=============where error happens
}
Notice that if I include the last line, I will get the error as follows:
g++ src/main.cpp src/CorpusExp.cpp src/MovieList.cpp src/MovieDictionary.cpp src/UserDictionary.cpp src/UserList.cpp src/UserUserSim.cpp -o recommend
src/UserUserSim.cpp: In member function ‘void UserUserSim::getTop(int&)’:
src/UserUserSim.cpp:81: error: no match for ‘operator<’ in ‘it_map < user_score_map. std::map<_Key, _Tp, _Compare, _Alloc>::end [with _Key = int, _Tp = float, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, float> >]()’
make: *** [recommend] Error 1
Barely new to c++, I checked some reference, I thought it is OK to iterate the map, otherwise, how could I copy some of the elements (like top k) out of the map into a vector?
Relational comparisons, like operators < , > and so on, are only available for random access iterators.
std::map iterators are bidirectional iterators, which is a much weaker spec than random access. You cannot use relational comparisons with bidirectional iterators. Map iterators are only comparable for equality. Use != comparison in your loop condition instead of <.
Moreover, it is always a good idea to use equality comparisons whenever you can and relational comparisons only when you really have to, i.e. rely on a weaker set of requirements whenever possible.
In the last line, try this:
for (it_map = user_score_map.begin(); it_map != user_score_map.end(); ++it_map)
You should follow this pattern in all your code.
You need to reduce the problem to a minimal amount of code! Most of the code seems to be entirely irrelavant to the problem!
The problem is that bidirectional iterators don't define a less-than relationship. You csn only compare them for equality or inequality. Just use
it != map.end()
instead of
it < map.end()
You need random-access iterators in order to compare them with "<", but std::map's iterators are not random-access (I'm not sure what they are, probably bidirectional).
Anyway, when iterating over a container, you should use "!=" for comparisson, not "<", whether with std::map iterators or with iterators of any other container.
EDIT after answered:
< should be provided for std::map. For more information about best practice, go for James McNellis's answer.
The code included in this question is poorly written. It is just because I am playing with SPOJ and the input data is strictly valid. The std::string approach is what I chose at first, but it turned out to be not fast enough.
Thank you.
I know I cannot use char[] directly with map, such as map<char[], int>. Thus I put it in a class. But it still can go through compilation. How to deal with that?
#include <stdio.h>
#include <map>
using namespace std;
class id {
public:
char v [30];
};
int main () {
map<id, int> m;
id a;
while (gets(a.v)) {
m[a]++;
}
return 0;
}
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = id]’:
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_map.h:418: instantiated from ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = id, _Tp = int, _Compare = std::less<id>, _Alloc = std::allocator<std::pair<const id, int> >]’
prog.cpp:15: instantiated from here
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
It seems it has something to do with comparison, but I am still in the dark.
First things first: never, ever use gets. It cannot be used safely and any program that uses it has a security vulnerability. There is no way to limit the number of characters that gets can write to the buffer that you provide it, so there is no way to prevent a buffer overflow. If you do need to use the C I/O library, you should use fgets instead, which allows you to specify the maximum number of characters to be read.
The reason that you are seeing this error is that the key type that you use must be comparable somehow. By default std::map uses operator<, which you do not define for id, hence the compilation error. You either need to define operator< to compare two id objects or you need to write a comparator functor that can be used to compare the two objects. Regardless which you choose, the comparator must provide a strict-weak ordering.
Since you are programming in C++, the ideal solution here is to use idiomatic C++:
std::map<std::string, int> m;
std::string s;
while (std::cin >> s) {
m[s]++;
}
std::string already provides operator< that provides a lexicographic ordering, so you don't need to define a comparator yourself.
You need to implement the < operator
class id {
public:
char v [30];
bool operator<(const id &rhs) const{
return strcmp(v,rhs.v) < 0;
}
};
EDIT: As a side note your code is a very poor way of doing things. See some of the answers for an explanation why.
In order to insert into the map, the map needs to be able to compare id's. You haven't provided an implementation of operator< that it can use. You have two options:
Provide one, example given by another answer here.
Use std::string instead.
I think you should use std::string. You can use the .c_str() method to convert it to a char array when you need to.
I have a nested set of ints but I cannot insert elements into the nested sets.
std::set<std::set<int> > centre_as_set = bitset_to_set(centre->second->bit_partitions);
std::set<std::set<int> >::iterator set_itr;
for ( set_itr = centre_as_set.begin(); set_itr != centre_as_set.end(); ++set_itr ) {
set_itr->insert(4);
std::set<int>::iterator node_itr;
for ( node_itr = set_itr->begin(); node_itr != set_itr->end(); ++node_itr ) {
std::cout << *node_itr;
}
}
}
The error is
Partition_standalone.cpp:612: error:
passing ‘const std::set, std::allocator >’
as ‘this’ argument of
‘std::pair, _Compare,
typename
_Alloc::rebind<_Key>::other>::const_iterator,
bool> std::set<_Key, _Compare,
_Alloc>::insert(const _Key&) [with _Key = int, _Compare = std::less, _Alloc =
std::allocator]’ discards
qualifiers
I can't quite decipher that template error, any help appreciated.
The elements in a set are not mutable and you are trying to use the non-const member function insert() on a const instance of std::set<int>. There is the following nice comment if you follow the iterator symbol to its declaration in stl_set.h:
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 103. set::iterator is required to be modifiable,
// but this allows modification of keys.
typedef typename _Rep_type::const_iterator iterator;
C++98 and C++03 allowed modification, but this is a defect and already fixed in non-ancient GCC versions and VC10. The mentioned defect report can be found here and will be incorporated into the next standard.
Use e.g. something like the following instead to add the value 4:
// Readability:
typedef std::set<int> IntSet;
typedef std::set<IntSet> IntSetSet;
// Helper:
IntSetSet add_value_to_sets(const IntSetSet& in, int i) {
IntSetSet ss;
IntSetSet::iterator set_itr;
for ( set_itr = in.begin(); set_itr != in.end(); ++set_itr ) {
IntSet s = *set_itr;
s.insert(4);
ss.insert(s);
}
return ss;
}
// ...
IntSetSet centre_as_set =
add_value_to_sets(bitset_to_set(centre->second->bit_partitions), 4);
Edit: This answer is wrong as per the comment of georg.
I dont have a compiler here, but the full declaration of std::set is:
template < class Key, class Compare = less<Key>,
class Allocator = allocator<Key> > class set;
The "Key" of the outermost set is "std::set". The Comparator is "std::less>", or short "operator<(set, set)" which is undefined. The compiler warns about this only on the first use/instantiation of the comparator.
I dont think there is a useful ordering/comparator for std::set's. You are better off using std::vector which doesnt order the elements and doesnt need a comparator.
Oh, and it is not allowed to change (at runtime) the set keys if this would affect the ordering. But that would be a runtime error, not a compile error.