2

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

Benjol
  • 63,995
  • 54
  • 186
  • 268
  • 1
    Despite the high votes for the answer below, I'm not convinced you have given enough information about the problem. I'm not sure if you're describing a memoization problem or a string-indexing problem. If you require full context (i.e. to make a wave form), the the problem isn't a "use a map??" problem as it is you need to find a way to efficiently store and search entire strings, and merely storing values won't help you here... basically, i need more info. don't know if anybody else does. – San Jacinto Sep 27 '09 at 20:51
  • right now, i recommend you examine suffix trees to see if this is closer to what you need. – San Jacinto Sep 27 '09 at 20:52
  • Agree with San Jacinto. One of the things that could help is, if you are confident on what your solution in C# would be (C# is much closer to C++ than F#), how would you implement it. How are you going to iterate your tree (in 2D?) to determine if you have a solution for a given point? finding the closest two pre-calculated points to use for the interpolation? A map is really nice for direct searches, but it will only search in one dimension (whatever the sorting algorithm you provide uses) – David Rodríguez - dribeas Sep 27 '09 at 23:20

6 Answers6

4

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  
maxaposteriori
  • 7,267
  • 4
  • 28
  • 25
2

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
  • 219,715
  • 46
  • 258
  • 445
  • 2
    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 Sep 27 '09 at 21:38
  • 3
    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 Sep 27 '09 at 21:39
  • @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 Sep 28 '09 at 06:53
1

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
  • 645
  • 7
  • 14
0

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
  • 8,774
  • 5
  • 43
  • 58
0

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

Satbir
  • 6,358
  • 6
  • 37
  • 52
-1

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
  • 557
  • 6
  • 7
  • Stars could not appear in (next) or (prev) – Red Sep 27 '09 at 22:44
  • 1
    `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 Sep 27 '09 at 22:46
  • 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 Sep 27 '09 at 23:00
  • 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 Sep 28 '09 at 06:47