views:

561

answers:

6
+2  Q: 

C++ map question

I have an integral position-based algorithm. (That is, the output of the algorithm is based on a curvilinear position, and each result is influenced by the values of the previous results).

To avoid recalculating each time, I would like to pre-calculate at a given sample rate, and subsequently perform a lookup and either return a pre-calculated result (if I land directly on one), or interpolate between two adjacent results.

This would be trivial for me in F# or C#, but my C++ is very rusty, (and wasn't even ever that good).

Is map the right construct to use? And could you be so kind as to give me an example of how I'd perform the lookup? (I'm thinking of precalculating in milimetres, which means the key could be an int, the value would be a double).

UPDATE OK, maybe what I need is a sorted dictionary. (Rolls up sleeves), pseudocode:

//Initialisation
fun MyFunction(int position, double previousresult) returns double {/*etc*/};
double lastresult = 0.0;
for(int s = startposition to endposition by sampledist)
{
    lastresult = MyFunction(s, lastresult);
    MapOrWhatever.Add(s, lastresult);
}
//Using for lookup
fun GetValueAtPosition(int position) returns double
{
    CheckPositionIsInRangeElseException(position);
    if(MapOrWhatever.ContainsKey(position)) 
        return MapOrWhatever[position];
    else
    {
        int i = 0;
        //or possibly something clever with position % sampledist...
        while(MapOrWhatever.Keys[i] < position) i+=sampledist;
        return Interpolate(MapOrWhatever, i, i+sampledist, position);
    }
}

Thinks... maybe if I keep a constant sampledist, I could just use an array and index it...

+4  A: 

A std::map sounds reasonable for memoization here provided your values are guaranteed not to be contiguous.

#include <map>

// ...

std::map<int, double> memo;
memo.insert(std::make_pair(5, 0.5));
double x = memo[5]; // x == 0.5
Andy
Hey, I just learned a new word - "memoization". Thanks!
Troubadour
key phrase: "if not contiguous"... and it sounds like it will be.
San Jacinto
also, just to be anal... that phrase should be "are guaranteed not to be contiguous"
San Jacinto
Good spot ...................
Andy
also, i think we both overlooked that we meant "continuous" and not "contiguous"
San Jacinto
A: 

please see my comment, but here is map documentation

http://www.cplusplus.com/reference/stl/map/

and important note than another poster did not mention is that if you use [] to search on a key that doesn't exist in the map, map will create an object so that there's something there.

edit: see docs here for this info http://msdn.microsoft.com/en-us/library/fe72hft9%28VS.80%29.aspx

instead, use find(), which returns an iterator. then test this iterator against map.end(), and if it is equal then there was no match.

San Jacinto
A: 

If you consider a map, always consider a vector, too. For values that aren't changed much (or even not at all) during the application running, a pre-sorted std::vector< std::pair<Key,Value> > (with O(N) lookup) more often than never performs faster for lookups than a std::map<key,Value> (with O(log N) lookup) - despite all the theory.

You need to try and measure.

sbi
This is only going to be the case for small N - and there's no conflict with theory here,as big-O notation describes relative performance for high N
bdonlan
If it's presorted and you're using a lookup method that takes advantage of that (std::lower_bound or similar), the vector is O(log N) too. With much lower constant factors. The downfall of the vector is inserting, if the list is built before use it's a clear winner.
puetzk
@bdonlan: Due to better locality of the data in conjunction with today's processor architectures, arrays sometimes excel even where big-O used to predict maps to perform better. (Look at this: http://stackoverflow.com/questions/454762/454782#454782) As I said, you need to _consider_ `std::vector` when you consider `std::map` and you need to measure.
sbi
A: 

The HASH_MAP is the best STL algoirthim for fast lookup than any other algorithims. But, filling takes little bit more time than map or vector and also it is not sorted. It takes constant time for any value search.

std::hash_map<int, double,> memo;
memo.insert(std::make_pair(5, 0.5));
memo.insert(std::make_pair(7,0.8));
.
.
.
hash_map<int,double>::iterator cur  = memo.find(5);
hash_map<int,double>::iterator prev = cur;
hash_map<int,double>::iterator next = cur;    
  ++next;
  --prev;

Interpolate current value with (next).second(), (prev).second() values..

Red
Stars could not appear in (next) or (prev)
Red
`hash_map` is not portable. TR1 does propose an `unordered_map` however, or you can use the boost implementation thereof. Also note that hash tables will have amortized `O(1)` insertion of a single element, provided the hash function is well-chosen, so with large enough datasets, a hash table will have _faster_ insertion than map.
bdonlan
As has been mentioned, hash_map isn't technically in the current STL. More importantly it is unordered, so interpolating between adjacent values in the map is likely a very bad idea.
Peter
I'd say, while hash maps are part of the STL, they aren't part of what of the STL got incorporated into the standard library. Otherwise I agree.
sbi
A: 

Refer : http://www.cplusplus.com/reference/stl/map/

You can use Map ,

typedef std::map<int,const double> mapType;

Performance of maps are like :

map:: find Complexity Logarithmic in size.

Beware of Operator [ ] in map

If x matches the key of an element in the container, the function returns a reference to its mapped value.

If x does not match the key of any element in the container, the function inserts a new element with that key and returns a reference to its mapped value. Notice that this always increases the map size by one, even if no mapped value is assigned to the element (the element is constructed using its default constructor).

sat
+1  A: 

std::map is probably fine as long as speed is not too critical. If the speed of the lookup is critical you could try a vector as mentioned above where you go straight to the element you need (don't use a binary search since you can compute the index from the position). Something like:

vector<double> stored;

// store the values in the vector
double lastresult = 0.0;
for(int s = startposition, index = 0; s <= endposition; s+=sampledist, ++index)
{
    lastresult = MyFunction(s, lastresult);
    stored[index] = lastresult;
}

//then to lookup
double GetValueAtPosition(int position) returns double
{
 int index = (position - startposition) / sampledist;
 lower = stored[index];
 upper = stored[index+1];
 return interpolate(lower, upper, position);
}
Corwin Joy