map custom key type

map custom key type

 

Map of the way to change the default comparison

https://www.cnblogs.com/zjfdlut/archive/2011/08/12/2135698.html

 

As we all know, map the STL with the underlying red-black tree-implemented generic prototype is as follows:

template <class _Key, class _Tp, class _Compare, class _Alloc>
class map {
......
}

Wherein _Key shows a comparison of the key (key), _ Tp represents the value (value), _ Compare a comparative manner, _Alloc represents memory allocator.

Generally, we always like to write the following code when writing the map:

map<int, char*>* my_map = new map<int, char*>;

It represents a bond to an int, a value of a string type. Here was not right _Compare and _Alloc be limited, because int is the C ++ built-in types, there is a default comparison mode, _Alloc also uses the STL

The default memory solutions. However, if the following structure:

struct Term{
char* str;
int hashCode;
};

Now we want to map this Term as a key, and assumed that the frequency corresponding to the value Term Term occurring (int type), can then write:

map<Term, int>* my_map = new map<Term, int>;

Clearly written map is not working properly, because struct Term is not a C ++ built-in types, the default does not know how to compare it. This time you need to modify the default way to compare the map:

template <class T>
struct Compare
{
int operator()(const T& x, const T& k) const{
if(x.hashCode >= k.hashCode) return 0;
else return 1;
}
};

Here is a function of the object (function object) in a manner to load the map comparison mode, the indication Term hashCode as a comparative embodiment, in order to find, insert and other operations on the red-black tree.

So that we can map written in the following form:

map<Term, int, Compare<Term> >* my_map = new map<Term, int, Compare<Term> >;

Such a map can be a normal operation, such as insertion operations:

Term my_term;
my_map->insert(make_pair(my_term, 1));

But above struct Compare Why write such a form, write that okay:

template <class T>
struct Compare
{
int operator()(const T& x, const T& k) const{
if(x.hashCode >= k.hashCode) return 1;
else return 0;
}
};

This is not acceptable. Why not first take a look at the map find the source code:

template <class _Key, class _Value, class _KeyOfValue, 
class _Compare, class _Alloc>
typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::iterator
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::find(const _Key& __k)
{
_Link_type __y = _M_header; // Last node which is not less than __k.
_Link_type __x = _M_root(); // Current node.

while (__x != 0)
if (!_M_key_compare(_S_key(__x), __k))
__y = __x, __x = _S_left(__x);
else
__x = _S_right(__x);

iterator __j = iterator(__y);
return (__j == end() || _M_key_compare(__k, _S_key(__j._M_node))) ? end() : __j;
}

Above _M_key_compare code indicates that our comparison function object, _S_key (__ x) represents taking __x node key, and to compare and __k.

if (!_M_key_compare(_S_key(__x), __k))
__y = __x, __x = _S_left(__x);

Said that if _S_key (__ x)> = __k ie, if key nodes is greater than or equal to find the key then __x equivalent to its left child, otherwise it is the right child.

But why does not directly equal to the time it returns, but continued to look for? Take, for example:

If we want to find the key to whether the node 10 when in the tree, starting from the root node to find, due to the 8 <10, then _M_key_compare returns 1, then the time,

Turn right subtree root, and since 10 == 10, _M_key_compare returns 0, then the left subtree of the steering, but the left subtree is empty, circulation is stopped.

 return (__j == end() || _M_key_compare(__k, _S_key(__j._M_node))) ? end() : __j;

At this time, since the __j indicates "10", this node (actually iterator), since __k 10, and the key is __j._M_node 10, _M_key_compare returns 0, there is seen ternary operator,

At this point return is __j, that means found. So our comparison function object required written:

When a node key is greater than or equal to find the inserted key, return 0 (false), otherwise it is 1 (true), which is determined by an internal source.

 

map custom key type

Original: https: //blog.csdn.net/y109y/article/details/82901710 

 

1. map defined
map of the STL is a template class, used to store the <key, value> pair of key data structures, which is defined as follows.

template < class Key,                                   //map::key_tpe
           class T,                                     //map::mapped_type
           class Compare = less<Key>,                   //map::key_compare
           class Alloc = allocator<pair<const Key, T>>  //map::allocator_type
           > class map;

 

The first parameter to store the key.

The second parameter is stored mapped value.

The third parameter is a function of the comparison object. map using it to determine the size of two of the key, and returns a result of type bool. With this function, the sequence elements can be determined following the map in the vessel and the two key elements are equal (! Comp (a, b) &&! Comp (b, a)), to ensure that no two map elements may have an equivalent key. Here, its default value is less <Key>, as defined below.

template <class T> 
struct less {
  bool operator() (const T& x, const T& y) const {return x < y;}
  typedef T first_argument_type;
  typedef T second_argument_type;
  typedef bool result_type;
};

 

Fourth parameter is used to define storage allocation model.

 

2. Simple Method: Overload operator <() operator
when we insert <key, value>, map will first come than the size of the key by comparing the function of the function object, and then the results were compared according to the ordered storage. c ++ standard library function map objects comparison function will inevitably use '<' operation, a method is thus in direct custom class overloads operator <() operator, as shown below.

#include <iostream>
#include <map>
#include <string>
using namespace std;

class Person{
public:
    string name;
    int age;

    Person(string n, int a){
        name = n;
        age = a;
    }

    bool operator<(const Person &p) const //注意这里的两个const
    {
        return (age < p.age) || (age == p.age && name.length() < p.name.length()) ;
    }
};

int main(int argc, char* argv[]){
    map<Person, int> group;
    group[Person("Mark", 17)] = 40561;
    group[Person("Andrew",18)] = 40562;
    for (auto ii = group.begin() ; ii != group.end() ; ii++)
        cout << ii->first.name 
        << " " << ii->first.age
        << " : " << ii->second
        << endl;
    return 0;
}

 

Here, we should be noted that, when overloaded operator <() {}, or whether the entire argument const Less function. Referring to less <Key> definition, less overall parameters and functions are const, then the called operator <() must also be the same requirement.

 

3. Other methods: comparison object function
if you do not overload operator <() is not to die? of course not. In addition to direct overloaded operator <(), we can directly compare the custom function function object.

First, a brief overview of the concept of function objects: the "C ++ Primer Plus" inside the function object can be incorporated as a function of any object used in the (). This includes the function name, and pointers to functions overloaded "operator ()" operator class object. Based on this, we propose three kinds of methods defined.

 

3.1 Method 1: Use std :: function
method using the std :: function. It is a generic, multi-state, type-safe function package, examples of which may be stored for any call the target entity (including a normal function, Lambda expressions, function pointers, and other function objects, etc.), and invoke copy, Methods as below.

 

#include <iostream>
#include <map>
#include <string>
#include <functional>
using namespace std;

class Person{
public:
    string name;
    int age;

    Person(string n, int a){
        name = n;
        age = a;
    }
};

bool MyCompare(const Person &p1, const Person &p2) {//普通的函数
    return (p1.age < p2.age) || (p1.age == p2.age && p1.name.length() < p2.name.length());
}

int main(int argc, char* argv[]){
    map<Person, int, function<bool(const Person &, const Person &)>> group(MyCompare); //需要在构造函数中指明
    group[Person("Mark", 17)] = 40561;
    group[Person("Andrew",18)] = 40562;
    for ( auto ii = group.begin() ; ii != group.end() ; ii++ )
        cout << ii->first.name 
        << " " << ii->first.age
        << " : " << ii->second
        << endl;
    return 0;
}

 

We use std :: function as builders to instantiate MyCompare (). At initialization, this example will be assigned the function pointed MyCompare () pointer. Thus, when the group performed affirm the need constructor functions specified instance.

Further, c ++ 11 adds a new keyword the decltype, which can be obtained from the type of hash function defined directly, and take it as a parameter. Thus, group of statements may be modified as follows.

map<Person, int, decltype(&MyCompare)> group(MyCompare);

 

3.2 Method 2: Overload operator () class
method that utilizes overloading operator () class, the comparison function can be packaged into a class called directly.

#include <iostream>
#include <map>
#include <string>
using namespace std;

class Person{
public:
    string name;
    int age;

    Person(string n, int a){
        name = n;
        age = a;
    }
};

struct MyCompare{  //Function Object
    bool operator()(const Person &p1, const Person &p2) const{
        return (p1.age < p2.age) || (p1.age == p2.age && p1.name.length() < p2.name.length());
    }
};

int main(int argc, char* argv[]){
    map<Person, int, MyCompare> group;
    group[Person("Mark", 17)] = 40561;
    group[Person("Andrew",18)] = 40562;
    for ( auto ii = group.begin() ; ii != group.end() ; ii++ )
        cout << ii->first.name 
        << " " << ii->first.age
        << " : " << ii->second
        << endl;

    return 0;
}

 

It is noteworthy that, when the group's statement cited the need to pass in the constructor no longer function object. Because the map keeps track of the class definition, when comparison requires, it can be dynamically configured to transfer data and objects.

 

3.3 Method 3: template customization less a function of
several methods before, no matter how we define, you need to specify the third parameter when declaring the group, there is a need to specify what methods it? Of course there are friends.

By defining the map shows that the default value of the third parameter is less <key>. Obvious, less <key> belongs to the template class. So, we can customize the template for it, as shown below.

#include <iostream>
#include <map>
#include <string>
using namespace std;

class Person{
public:
    string name;
    int age;

    Person(string n, int a){
        name = n;
        age = a;
    }
};

template <> //function-template-specialization
    struct less<Person>{
    public :
        bool operator()(const Person &p1, const Person &p2) const {
            return (p1.age < p2.age) || (p1.age == p2.age && p1.name.length() < p2.name.length());
        }
};

int main(int argc, char* argv[]){
    map<Person, int> group; //无需指定第三个参数啦
    group[Person("Mark", 17)] = 40561;
    group[Person("Andrew",18)] = 40562;
    for ( auto ii = group.begin() ; ii != group.end() ; ii++ )
        cout << ii->first.name 
        << " " << ii->first.age
        << " : " << ii->second
        << endl;

    return 0;
}

 

================ End

 

Guess you like

Origin www.cnblogs.com/lsgxeva/p/11222986.html