web-dev-qa-db-fra.com

Vérifier l'existence dans std :: map - count vs find

Il semble donc qu'il existe deux méthodes généralement acceptables pour déterminer s'il existe ou non une clé dans un std :: map:

map.find(key) != map.end()
map.count(key) > 0

L'un est-il plus efficace que l'autre? Plus précisément, le concept de count () pourrait être interprété comme signifiant que la méthode itérera sur chaque clé, en totalisant un nombre total (et en raison de la définition de std :: map, ce nombre total sera toujours 0 ou 1). Count () est-il garanti de "s'arrêter" après un match, fonctionnant avec la même complexité qu'un find ()?

41
dolphy

Puisqu'une carte ne peut avoir au plus qu'une clé, count s'arrêtera essentiellement après qu'un élément a été trouvé. Cependant, étant donné les conteneurs plus généraux tels que les multimaps et les multisets, find est strictement meilleur si vous vous souciez seulement de savoir si l'élément some avec cette clé existe, car il peut vraiment s'arrêter une fois le premier l'élément correspondant a été trouvé.

En général, count et find utiliseront les méthodes de recherche spécifiques au conteneur (traversée d'arbre ou recherche de table de hachage), qui sont toujours assez efficaces. C'est juste que count doit continuer à itérer jusqu'à la fin de la plage égale, contrairement à find. De plus, votre code doit documenter l'intention, donc si vous voulez trouver quelque chose, utilisez find.

42
Kerrek SB

Selon le code source, je suggère d'utiliser find. Voir le code source.

Dans GCC, le code suit (stl_map.h):

    const_iterator
    find(const key_type& __x) const
    { return _M_t.find(__x); }

    size_type                                                                              
    count(const key_type& __x) const                                                       
    { return _M_t.find(__x) == _M_t.end() ? 0 : 1; }  

Dans Visual Studio sur la plate-forme Windows, le code suit (xtree):

    const_iterator find(const key_type& _Keyval) const
    {   // find an element in nonmutable sequence that matches _Keyval
        const_iterator _Where = lower_bound(_Keyval);
        return (_Where == end()
            || _DEBUG_LT_PRED(this->_Getcomp(),
                _Keyval, this->_Key(_Where._Mynode()))
                    ? end() : _Where);
    }

    //....

    const_iterator lower_bound(const key_type& _Keyval) const
    {   // find leftmost node not less than _Keyval in nonmutable tree
        return (const_iterator(_Lbound(_Keyval), this));
    }

    //....

    _Nodeptr _Lbound(const key_type& _Keyval) const
    {   // find leftmost node not less than _Keyval
        _Nodeptr _Pnode = _Root();
        _Nodeptr _Wherenode = this->_Myhead;    // end() if search fails

        while (!this->_Isnil(_Pnode))
            if (_DEBUG_LT_PRED(this->_Getcomp(), this->_Key(_Pnode), _Keyval))
                _Pnode = this->_Right(_Pnode);  // descend right subtree
            else
                {   // _Pnode not less than _Keyval, remember it
                _Wherenode = _Pnode;
                _Pnode = this->_Left(_Pnode);   // descend left subtree
                }

        return (_Wherenode);    // return best remembered candidate
    }

    //..........................................
    //..........................................

    size_type count(const key_type& _Keyval) const
    {   // count all elements that match _Keyval
        _Paircc _Ans = equal_range(_Keyval);
        size_type _Num = 0;
        _Distance(_Ans.first, _Ans.second, _Num);
        return (_Num);
    }

    //....

    _Pairii equal_range(const key_type& _Keyval) const
    {   // find range equivalent to _Keyval in nonmutable tree
        return (_Eqrange(_Keyval));
    }

    //....

    _Paircc _Eqrange(const key_type& _Keyval) const
    {   // find leftmost node not less than _Keyval
        _Nodeptr _Pnode = _Root();
        _Nodeptr _Lonode = this->_Myhead;   // end() if search fails
        _Nodeptr _Hinode = this->_Myhead;   // end() if search fails

        while (!this->_Isnil(_Pnode))
            if (_DEBUG_LT_PRED(this->_Getcomp(), this->_Key(_Pnode), _Keyval))
                _Pnode = this->_Right(_Pnode);  // descend right subtree
            else
                {   // _Pnode not less than _Keyval, remember it
                if (this->_Isnil(_Hinode)
                        && _DEBUG_LT_PRED(this->_Getcomp(), _Keyval,
                        this->_Key(_Pnode)))
                    _Hinode = _Pnode;   // _Pnode greater, remember it
                _Lonode = _Pnode;
                _Pnode = this->_Left(_Pnode);   // descend left subtree
                }

        _Pnode = this->_Isnil(_Hinode) ? _Root()
            : this->_Left(_Hinode); // continue scan for upper bound
        while (!this->_Isnil(_Pnode))
            if (_DEBUG_LT_PRED(this->_Getcomp(), _Keyval, this->_Key(_Pnode)))
                {   // _Pnode greater than _Keyval, remember it
                _Hinode = _Pnode;
                _Pnode = this->_Left(_Pnode);   // descend left subtree
                }
            else
                _Pnode = this->_Right(_Pnode);  // descend right subtree

        const_iterator _First = const_iterator(_Lonode, this);
        const_iterator _Last = const_iterator(_Hinode, this);
        return (_Paircc(_First, _Last));
    }
11
Bright Chen

Si vous voulez simplement savoir si la clé existe ou non, et ne vous souciez pas de la valeur, il est préférable d'utiliser map::count car il ne renvoie qu'un entier. map::find renvoie un itérateur, donc en utilisant count, vous économiserez la construction d'un itérateur.

3
Sagar Jha