【问题标题】:Efficient search for an element other than the one used for ordering in std::set高效搜索除 std::set 中用于排序的元素之外的元素
【发布时间】:2020-10-06 09:33:54
【问题描述】:

考虑以下集合实现。在这里,我根据 fScore 参数对集合进行了排序。如果我想在“NodeData”中搜索特定“id”的元素,我应该怎么做。 我知道我可以使用“find”在 O(logn) 的集合中搜索“fScore”的任何元素。 有没有比线性搜索(下面实现)更有效的方法来搜索“id”(时间更短)?

#include<iostream>
#include<algorithm>
#include<iterator>
#include<set>
#include<stdlib.h>
#include<vector>
struct NodeData{
        int id;
        int parent;
        double fScore, gScore, hScore;
        std::vector<double> nScores;

        NodeData(const int& idIn = 0,
                const int& parentIn = -1,
                const double& fIn = 1,
                const double& gIn = 1,
                const double& hIn = 1):id(idIn), parent(parentIn), 
                fScore(fIn), gScore(gIn), hScore(hIn)
        {
        }
bool operator<(const NodeData& rhs) const {
    return fScore < rhs.fScore;
}
};

class test
{
        public:
        std::set<NodeData> NodeList;

};

int main()
{
        test q;
    for(int i=1;i<=5;i++)
    {
        NodeData n1 = {i,1,i,1,1};
        q.NodeList.insert(n1);
    }
    std::set<NodeData>::iterator it;
    //search for node with fScore 1 - cost O(logn)
    it = q.NodeList.find(1);    
     if(it != q.NodeList.end()){
    std::cout<<"node with fScore 1 found. id = "<<it->id<<std::endl;
    }
    else{   
    std::cout<<"node not found = "<<std::endl;
    }
    //searching for id=3 - Linear search - cost O(n) 
    int searchId = 3;
    std::set<NodeData>::iterator it1 = q.NodeList.begin();
    while(it1 != q.NodeList.end())
    {
        if(it1->id == searchId)
        {
            std::cout <<"found node with id = "<<it1->id<<std::endl;    
        }
    it1++;
    }   
}

【问题讨论】:

    标签: performance search iterator set


    【解决方案1】:

    您的set 是否经常更改?如果没有 - 你可以考虑为你的集合元素建立一个“索引” - unordered_map&lt;&gt; 任何你需要的字段。

    维护这样的“索引”是有成本的,你应该看看它是否超过了更快的搜索。

    【讨论】:

    • 感谢您的建议。我将此集合用于优先队列。我买不起另一个数据结构,因为在推送和弹出操作期间集合会发生很大变化。
    【解决方案2】:

    如果不使用不同/额外的数据结构,您将无法实现这一点。如果您使用 C++ 并且可以使用库,则可以在 Boost multi-index containers library 中找到此功能。

    【讨论】:

      【解决方案3】:

      添加到Falk's answer,这是一个如何使用 Boost.MultiIndex 完成此操作的示例:

      Live On Coliru

      #include <iostream>
      #include <algorithm>
      #include <iterator>
      #include <stdlib.h>
      #include <vector>
      #include <boost/multi_index_container.hpp>
      #include <boost/multi_index/identity.hpp>
      #include <boost/multi_index/member.hpp>
      #include <boost/multi_index/ordered_index.hpp>
      
      struct NodeData{
          int id;
          int parent;
          double fScore, gScore, hScore;
          std::vector<double> nScores;
      
          NodeData(const int& idIn = 0,
                   const int& parentIn = -1,
                   const double& fIn = 1,
                   const double& gIn = 1,
                   const double& hIn = 1):id(idIn), parent(parentIn), 
                   fScore(fIn), gScore(gIn), hScore(hIn)
          {
          }
          
          bool operator<(const NodeData& rhs) const {
              return fScore < rhs.fScore;
          }
      };
      
      class test
      {
              public:
              typedef boost::multi_index_container<
                  NodeData,
                  boost::multi_index::indexed_by<
                      boost::multi_index::ordered_unique<
                          boost::multi_index::identity<NodeData>
                      >,
                      boost::multi_index::ordered_unique<
                          boost::multi_index::member<NodeData, int, &NodeData::id>
                      >
                  >
              > NodeListType;
              NodeListType NodeList;
      
      };
      
      int main()
      {
          test q;
          for(int i=1;i<=5;i++)
          {
              NodeData n1 = {i,1,double(i),1,1};
              q.NodeList.insert(n1);
          }
          test::NodeListType::iterator it;
          //search for node with fScore 1 - cost O(logn)
          it = q.NodeList.find(1);    
          if(it != q.NodeList.end()){
          std::cout<<"node with fScore 1 found. id = "<<it->id<<std::endl;
          }
          else{   
          std::cout<<"node not found = "<<std::endl;
          }
          //searching for id=3 on second index - cost O(logn) 
          int searchId = 3;
          test::NodeListType::nth_index<1>::type::iterator it1 = q.NodeList.get<1>().find(searchId);
          if(it1 != q.NodeList.get<1>().end()){
              std::cout <<"found node with id = "<<it1->id<<std::endl;    
          }   
      }
      

      如果您对NodeData::id 使用散列索引而不是有序索引,则查找是恒定的(平均而言)。

      【讨论】:

        猜你喜欢
        • 2020-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-22
        • 2013-10-29
        相关资源
        最近更新 更多