使用锁和 STL 算法对 C++ 向量进行排序,或者编写一个没有锁的更复杂的算法

sort c++ vector using a lock and STL algo or write a more complex algo with no lock?

本文关键字:算法 复杂 一个 STL C++ 向量 排序 或者      更新时间:2023-10-16

有没有一种有效的方法来比较两个执行 STL 类型操作的向量,这样我就不必对它们进行排序或复制它们? 问题是排序导致我不得不在 getIntersection 方法上创建一个锁,理想情况下我想避免这种情况,因为它实际上只是读取数据结构并在其中查找数据而不是更改它。sort 方法更改了数据结构,因此需要同步该方法的其他调用。 我可能只需要创建一个副本,但这可能是一个大副本,但可能比锁定更快,但不确定。因此,我的问题是搜索排序的向量是否比仅仅取锁或副本的价格更有效。 请考虑以下示例:

class X
{

  public:
  struct TestX
  {
     long id;
     .......... // other items
  };

   void getIntersectionByID ( vector<TextX>& result, const vector<TestX>& ids)
   {
      return getItemsByIntersection<long,TestX>( result, _v1, ids, &TestX::id);
      return false; 
   }

   private:
    vector<TestX> _v1;  // assume this is populated with data
};

  // generic pred to do weak ordering on a structure by a generic field
// this is a generalized less than function which can be used for ordering
// and other equality operations
template<typename T, typename K>
struct byField
{
  public:
  byField(T K::* idMember) : idMember_(idMember) {}    
  bool operator() (const K& obj1, const K& obj2)
  {
    return ( obj1.*idMember_ < obj2.*idMember_ );
  }
  private:
  T K::* idMember_;     
};

    template <typename T, typename K>
bool getItemsByIntersection ( std::vector<K>& retds, std::vector<K>& ds, const std::vector<T>& values, T K::* field  )
{
  //create the vector of structs to use for comparison
  typename std::vector<K> searchCriteria(values.size());
  typename std::vector<K>::iterator itS =  searchCriteria.begin();
  // assign the item to the vector
  for (typename std::vector<T>::const_iterator it = values.begin(), itEnd = values.end(); it != itEnd; ++it,++itS)
  {
    (*itS).*field = *it;
  }
  // reserve half the size of the total ds just to be safe
  typename std::vector<K> tmp;
  tmp.reserve(ds.size()/2);
  sort( ds.begin(), ds.end(), byField<T,K>(field) );
  sort( searchCriteria.begin(), searchCriteria.end(), byField<T,K>(field) );
  setGrep ( ds.begin(), ds.end(), searchCriteria.begin(), searchCriteria.end(), std::back_inserter(tmp), byField<T,K>(field) );
 // don't change state until the very end, any existing contents in retds are destroyed
  retds.swap(tmp);
  if ( !retds.empty() )
  {
    return true;
  }
  return false;
}

    /  this is a set grep meaning any items that are in set one
    // will be pulled out if they match anything in set 2 based on operator pred 
    template<typename _InputIterator1, typename _InputIterator2,
      typename _OutputIterator, typename _Compare>
      _OutputIterator
    setGrep(_InputIterator1 __first1, _InputIterator1 __last1,
        _InputIterator2 __first2, _InputIterator2 __last2,
        _OutputIterator __result, _Compare __comp)
    {
      while (__first1 != __last1 && __first2 != __last2)
        if (__comp(*__first1, *__first2))
          ++__first1;
        else if (__comp(*__first2, *__first1))
          ++__first2;
        else
        {
          *__result = *__first1;
          ++__first1;
          ++__result;
        } 
      return __result;
    }

如果你有小向量,你可以写一些东西来解决问题,但如果向量没有排序,就没有办法避免n*n比较。假设您在两个向量中有 1,000,000 个元素,即 1,000,000,000,000,000 次比较操作。

如果你只需要相等/不相等,你可以复制两者,对副本进行排序,比较它们并销毁副本......

你可以复印。要么以明显的方式复制为向量然后排序,要么向量可能包含大量重复

std::set<T,pred> s1(v1.begin(), v1.end());
std::set<T,pred> s2(v2.begin(), v2.end());
std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), std::back_inserter(tmp), pred());

改用unordered_set可能会更快,而且内存也更少,因为您只需要其中一个集合的"副本"。但是,您必须编写一个哈希函数,这可能并不容易,具体取决于您的谓词的作用。您还必须编写交叉代码,但这很简单。

其他可能的选择:在填充完成后立即对v1进行排序;X使用set而不是vector;将条件作为set而不是vector提供。它们是否适用取决于X和/或呼叫者是否可以看到pred。如上所述,如果您可以编写哈希器,则可以将set替换为unordered_set