C++ 如何提高键类型为std::string的映射查找的性能?

C++ 如何提高键类型为std::string的映射查找的性能?,c++,dictionary,optimization,visual-c++,stdmap,C++,Dictionary,Optimization,Visual C++,Stdmap,我使用的是std::map(VC++实现),通过map的find方法进行查找有点慢 键类型是std::string 我是否可以通过映射的自定义键比较覆盖来提高此std::map查找的性能?例如,在比较数据之前,std::string

我使用的是
std::map
(VC++实现),通过map的find方法进行查找有点慢

键类型是
std::string

我是否可以通过映射的自定义键比较覆盖来提高此
std::map
查找的性能?例如,在比较数据之前,
std::string
string::size()比较

还有其他加快比较的方法吗

在我的情况下,映射将始终包含<15个元素,但它被不间断地查询,性能至关重要。也许有一个更好的数据结构,我可以使用,这会更快

更新:映射包含文件路径


更新2:映射的元素经常变化。

如果可能的话,第一件事是尝试使用哈希映射-标准字符串比较不会首先检查大小(因为它是按字典顺序进行比较的),但是编写自己的映射代码是最好避免的。从你的问题听起来,你不需要迭代范围;在这种情况下,map没有任何哈希值,而map没有

这也取决于你的地图上有什么样的钥匙。它们通常很长吗?“有点慢”是什么意思?如果您还没有分析代码,很可能是另一个需要时间的部分


更新:嗯,程序中的瓶颈是map::find,但是map的元素总是少于15个。这让我怀疑这个资料有点误导人,因为在这么小的地图上找到一个应该不会太慢。事实上,map::find应该非常快,只是分析的开销可能会超过find调用本身。我必须再问一次,你确定这真的是你计划中的瓶颈吗?你说字符串是路径,但你没有在这个循环中进行任何操作系统调用、文件系统访问和磁盘访问?其中任何一个都应该比小地图上的map::find慢几个数量级。实际上,任何获取字符串的方法都应该比map::find慢。

std::map的比较器不是std::等于它的std::less,我不确定短路
如果总有<15个元素,也许您可以使用std::string以外的键?

以下是一些您可以考虑的事项:


0)您确定这就是性能瓶颈所在吗?比如Quantify、Cachegrind、gprof之类的结果?因为在这样的smap地图上查找应该是相当快的


1) 您可以重写用于比较std::map中的键的functor,还有第二个模板参数可以执行此操作。我怀疑你能比操作符做得更好,正如所说的
集合中使用的操作符是
你可以尝试使用排序向量(),这可能会更快(当然你必须这样做)

认为它会更快的原因:

  • 更少的内存分配和释放(向量将扩展到使用的最大大小,然后重用释放的内存)
  • 随机访问的二进制查找应该比树遍历更快(特别是由于数据的局部性)
  • 认为速度会慢一些的原因:

  • 删除和添加意味着在内存中移动字符串,因为
    string
    swap
    非常有效,而且数据集的大小很小,这可能不是问题

  • hash_-map
    不是标准的,请尝试使用tr1中可用的
    unordered_-map
    (如果您的工具链还没有,它在boost中可用)


    对于少量字符串,最好使用
    vector
    ,因为
    map
    通常作为树实现。

    Motti有一个很好的解决方案。但是,我很确定对于<15个元素,映射不是正确的方法,因为它的开销总是比使用适当哈希方案的简单查找表的开销要大。在您的例子中,仅按长度散列可能就足够了,如果这仍然会产生冲突,请对所有相同长度的条目进行线性搜索


    要确定我是否正确,当然需要一个基准测试,但我非常确定它的结果。

    根据使用情况,您可以使用其他一些技术。例如,我们有一个应用程序需要跟上超过一百万个不同的文件路径。问题在于,有数千个对象需要保留这些文件路径的小映射

    由于向数据集添加新文件路径是一项不常见的操作,因此在向系统添加路径时,会搜索主地图。如果未找到路径,则会添加该路径并返回一个新的已排序整数(从1开始)。如果路径已经存在,则返回先前分配的整数。然后,每个对象维护的每个映射都从基于字符串的映射转换为整数映射。这不仅大大提高了性能,而且还减少了内存使用量,因为它没有这么多重复的字符串副本

    当然,这是一个非常具体的优化。但是,当谈到性能改进时,您经常发现自己必须针对特定问题制定量身定制的解决方案


    我讨厌字符串:)它们的比较速度并不慢,但它们确实会在高性能软件上破坏CPU缓存。

    首先,关闭所有评测和调试开关。这些可以大大降低STL的速度

    如果不是这样,部分问题可能是字符串的前80-90%是相同的。这对于map来说当然不是坏事,但对于字符串比较来说却是坏事。如果是这种情况,您的搜索可能需要更长的时间

    例如,在这段代码中,find()可能会导致两次字符串比较,但每次比较都会在compa之后返回
    struct comp {
        bool operator()(const std::string& lhs, const std::string& rhs)
        {
            if (lhs.length() < rhs.length())
                return true;
            return lhs < rhs;
        }
    };
    
    string a = "z";
    string b = "aa";
    
    struct comp {
        bool operator()(const std::string& lhs, const std::string& rhs)
        {
            if (lhs.length() != rhs.length())
                return lhs.length() < rhs.length();
            return lhs < rhs;
        }
    };
    
    map<string,int> names;
    names["larry"] = 1;
    names["david"] = 2;
    names["juanita"] = 3;
    
    map<string,int>::iterator iter = names.find("daniel");
    
    map<string,int> names;
    names["/usr/local/lib/fancy-pants/share/etc/doc/foobar/longpath/yadda/yadda/wilma"] = 1;
    names["/usr/local/lib/fancy-pants/share/etc/doc/foobar/longpath/yadda/yadda/fred"] = 2;
    names["/usr/local/lib/fancy-pants/share/etc/doc/foobar/longpath/yadda/yadda/barney"] = 3;
    
    map<string,int>::iterator iter = names.find("/usr/local/lib/fancy-pants/share/etc/doc/foobar/longpath/yadda/yadda/betty");
    
    class HashedString
    {
      unsigned m_hash;
      std::string m_string;
    
    public:
      HashedString(const std::string& str)
        : m_hash(HashString(str))
        , m_string(str)
      {};
      // ... copy constructor and etc...
    
      unsigned GetHash() const {return m_hash;}
      const std::string& GetString() const {return m_string;}
    };
    
    struct comp
    {
      bool operator()(const HashedString& lhs, const HashedString& rhs)
      {
        if(lhs.GetHash() < rhs.GetHash()) return true;
        if(lhs.GetHash() > rhs.GetHash()) return false;
        return lhs.GetString() < rhs.GetString();
      }
    };
    
    #define "STRING_1" STRING_1