【问题标题】:Determining if two vectors contain two adjacent items the same确定两个向量是否包含两个相同的相邻项
【发布时间】:2013-12-28 08:05:17
【问题描述】:

我有一个问题,涉及确定两个向量是否包含相同的两个元素。元素可以在向量中的任何位置,但它们必须是相邻的。

为更多示例编辑

例如,以下两个向量在比较时会返回 false。

向量 1 = [ 0, 1, 2, 3, 4, 6 ]

向量 2 = [ 1, 4, 2, 0, 5, 3 ]

但以下两个会返回 true:

向量 1 = [ 0, 1, 2, 3, 4, 5 ]

向量 2 = [ 4, 2, 1, 5, 0, 3 ]

因为第一个向量中的 1,2 将对应于第二个向量中的 2,1。

正确:

向量 1 = [ 0, 1, 2, 3, 4, 5 ]

向量 2 = [ 1, 4, 2, 0, 5, 3 ]

{5,0} 是一对,尽管围绕向量循环(我最初说这是错误的,感谢您发现“来自莫斯科的弗拉德”)。

正确:

向量 1 = [ 0, 1, 2, 3, 4, 5 ]

向量 2 = [ 4, 8, 6, 2, 1, 5, 0, 3 ]

{2,1} 仍然是一对,即使它们不在同一位置

实际应用是我有一个多边形(面),N 个点存储在一个向量中。为了确定一组多边形是否完全包围了一个 3D 体积,我测试了每个面以确保每条边都被另一个面共享(其中一条边由两个相邻点定义)。

因此,Face 包含指向 Points 的指针向量...

std::vector<Point*> points_;

为了检查一个 Face 是否被包围,Face 包含一个成员函数...

bool isSurrounded(std::vector<Face*> * neighbours)
{
    int count = 0;
    for(auto&& i : *neighbours)     // for each potential face
        if (i != this)              // that is not this face
            for (int j = 0; j < nPoints(); j++) // and for each point in this face
                for (int k = 0; k < i->nPoints(); k++ ) // check if the neighbour has a shared point, and that the next point (backwards or forwards) is also shared
                    if ( ( this->at(j) == i->at(k) )        // Points are the same, check the next and previous point too to make a pair
                       && (    ( this->at((j+1)%nPoints()) == i->at((k+1)%(i->nPoints())) )
                            || ( this->at((j+1)%nPoints()) == i->at((k+i->nPoints()-1)%(i->nPoints())) )))
                        { count++; }
    if (count > nPoints() - 1) // number of egdes = nPoints -1
        return true;
    else
        return false;
}

现在,显然这段代码很糟糕。如果我在 2 周后回到这个问题,我可能不会理解它。那么面对原来的问题,你会如何整齐的检查这两个向量呢?

请注意,如果您尝试破译提供的代码。 at(int) 返回面中的点,nPoints() 返回面中的点数。

非常感谢。

【问题讨论】:

  • 啊——另一个使用“2周规则”的人。
  • 我应该指定两个向量可以是任意长度。
  • 再举几个“不匹配”和“匹配”的例子(不同的长度,不同的位置),包括极端情况(开始/结束——它们是一对吗?)

标签: c++ algorithm c++11 vector stl


【解决方案1】:

效率不高,但有可能跟随。

bool comparePair ( pair<int,int> p1, pair<int,int> p2 ) {
  return ( p1.first == p2.first && p1.second == p2.second )
           || ( p1.second == p2.first && p1.first == p2.second );
}

//....

vector< pair<int,int> > s1;
vector< pair<int,int> > s1;
vector< pair<int,int> > intersect( vec1.size() + vec2.size() );

for ( int i = 0; i < vec1.size()-1; i++ ) {
  pair<int, int> newPair;
  newPair.first = vec1[i];
  newPair.first = vec1[i+1];
  s1.push_back( newPair );
}

for ( int i = 0; i < vec2.size()-1; i++ ) {
  pair<int, int> newPair;
  newPair.first = vec2[i];
  newPair.first = vec2[i+1];
  s2.push_back( newPair );
}

auto it = std::set_intersection ( s1.begin(), s1.end(), s2.begin(), s2.end(), 
                                   intersect.begin(), comparePair );

return ( it != intersect.begin() ); // not sure about this.

【讨论】:

  • 我喜欢它,它比我的稍微整洁,因为它删除了一个 for 循环。但它也假设 vec1 和 vec2 的大小相同,我应该指定 - 并非总是如此
  • 啊,是的,但这突出了另一个问题,即两个元素可能不在向量中的同一位置。可能是 vec1 中的前两个元素与 vec2 中的后两个元素匹配。
  • @JamesHawkes 编辑了我的答案。
  • std::set_intersection 期望对其输入进行排序。还有一个小错误,我猜是newPair.second = vec1[i+1];newPair.second = vec2[i+1]; 的意思。
【解决方案2】:

如果我理解你的问题:

std::vector<int> a, b;
std::vector<int>::iterator itB = b.begin();
std::vector<int>::iterator itA;
std::vector<std::vector<int>::iterator> nears;
std::vector<int>::iterator near;
for(;itB!=b.end() ; ++itB) {
    itA = std::find(a.begin(), a.end(), *itB);
    if(nears.empty()) {
        nears.push_back(itA);
    } else {
     /* there's already one it, check the second */  
      if(*(++nears[0])==*itA && itA != a.end() {
        nears.push_back(itA);
      } else {
        nears.clear();
        itB--;
      }         
    }
    if(nears.size() == 2) {
      return true;
    } 
}
return false;

【讨论】:

  • 我看到了你来自的角度,本质上是创建临时存储来跟踪一对。但是您还必须检查--nears[0] 以了解元素以相反顺序形成一对的情况(我认为?)。这是一个不错的角度,但我真的在寻找更简洁的解决方案。
【解决方案3】:
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>

using namespace std;
class AdjacentSort
{
public:
    AdjacentSort(const vector<int>& ref);
    ~AdjacentSort();

    bool operator()(int e1,int e2) const;
private:
    const vector<int>& ref_;
};

AdjacentSort::AdjacentSort(const vector<int>& ref):
    ref_(ref)
{
}

bool AdjacentSort::operator()(int e1, int e2) const
{
    auto it1 = find(ref_.begin(),ref_.end(),e1);
    auto it2 = find(ref_.begin(),ref_.end(),e2);

    return distance(it1,it2) == 1;
}

AdjacentSort::~AdjacentSort()
{
}

int main()
{
    vector<int> vec {1,2,3,4,5};
    vector<int> vec2 {1,3,5,4,2};

    AdjacentSort func(vec);
    auto it = adjacent_find(vec2.begin(),vec2.end(),func);

    cout << *it << endl;

    return 0;
}

返回找到两个相邻数字的第一个元素,否则返回结束迭代器。

【讨论】:

  • 这是我最喜欢的答案之一 - 特别是如果我可以取消类并用 lambda 函数替换 func。
  • 是的,这是可能的,但我发现在仿函数中单独执行它更优雅。
【解决方案4】:

如果您的元素是同一组元素,则为每个元素分配索引。 (在伪中没有提到极端情况):-

for(int i=0;i<vect1.size;i++) {

   adj[vect1[i]][0] = vect1[i-1];
   adj[vect2[i]][1] = vect2[i+1];
}

for(int j=0;j<vect2.size();j++) {

    if(arr[vect2[i]][0]==(vect2[j-1] or vect[j+1]))
       return true
    if(arr[vect2[i]][1]==(vect2[j-1] or vect[j+1]))
       return true

}

【讨论】:

    【解决方案5】:

    如果我理解正确这两个向量

    std::vector<int> v1 = { 0, 1, 2, 3, 4, 5 };
    std::vector<int> v2 = { 3, 5, 2, 1, 4, 0 };
    

    包含相邻的相等元素。它们是第一个向量中的对 {1, 2 } 和第二个向量中的对 {2, 1 },尽管这些对在向量中的位置不同。

    事实上,您已经命名了可用于此任务的适当标准算法。它是 std::adjacent_find。例如

    #include <iostream>
    #include <iomanip>
    #include <algorithm>
    #include <vector>
    
    
    int main() 
    {
        std::vector<int> v1 = { 0, 1, 2, 3, 4, 5 };
        std::vector<int> v2 = { 3, 5, 2, 1, 4, 0 };
    
        bool result =
            std::adjacent_find( v1.begin(), v1.end(),
                [&v2]( int x1, int y1 )
                {
                    return std::adjacent_find( v2.begin(), v2.end(),
                    [=]( int x2, int y2 ) 
                    { 
                        return ( x1 == x2 && y1 == y2 || x1 == y2 && y1 == x2 );
                    } ) != v2.end();
                } ) != v1.end();
    
        std::cout << "result = " << std::boolalpha << result << std::endl;
    
        return 0;
    }
    

    【讨论】:

    • 我认为这是一个有趣的想法。但是,OP 的问题要求向量的最后一个元素和第一个元素应该被视为相邻元素(这不是很清楚)。 std::adjacent_if 没有这样做,但几行额外的代码应该足以测试这个案例并完成你的答案。
    • @Cassio 如果您说的确实正确,那么这两个向量 Vector 1 = [ 0, 1, 2, 3, 4, 5 ] Vector 2 = [ 1, 4, 2, 0, 5, 3 ] 有相邻的相等对 {0, 5}。然而,在原帖中并没有说这对存在。
    • 你说的都是对的,我的意思是最后一个元素和第一个元素应该被认为是相邻的,我确实举了一个不好的例子。我已经编辑了我的帖子以反映这一点。这是一个非常有趣的答案,我将不得不更深入地研究 std::adjacent_find()。
    【解决方案6】:

    这是我对这个问题的尝试。很简单,遍历a,在b中找到相同的元素,然后将a中的下一个元素与b中我们位置前后的元素进行比较。

    如果它比它需要的更冗长一些,那么这个函数可以被任何容器调用。唯一的要求是容器的迭代器必须是双向的。

        #include <vector>
        #include <iostream>
        #include <algorithm>
        #include <list>
    
        using namespace std;
    
        template <class Iter>
        pair<Iter, Iter> get_neighbors(Iter begin, Iter current, Iter end)
        {
            auto p = make_pair(end, next(current));
            if(current != begin)
                p.first = prev(current);
            return p;
        }
    
        template <class Iter1, class Iter2>
        bool compare_if_valid(Iter1 p1, Iter1 end1, Iter2 p2)
        {
            return p1 != end1 && *p1 == *p2;
        }
    
        template <class C1, class C2>
        auto neighbors_match(const C1 & a, const C2 & b) ->
            decltype(make_pair(begin(a), begin(b)))
        {
            for(auto i = begin(a); i != end(a) && next(i) != end(a); ++i)
            {
                auto pos_in_b = find(begin(b), end(b), *i);
                if(pos_in_b != end(b))
                {
                    auto b_neighbors = get_neighbors(begin(b), pos_in_b, end(b));
                    if(compare_if_valid(b_neighbors.first, end(b), next(i)))
                        return {i, b_neighbors.first};
                    else if(compare_if_valid(b_neighbors.second, end(b), next(i)))
                        return {i, pos_in_b};
                }
            }
            return {end(a), end(b)};
        }
    
        int main()
        {
            vector<int> a = {0, 1, 2, 3, 4, 5};
            vector<int> b = {1, 4, 2, 0, 5, 3};
            cout << boolalpha << (neighbors_match(a, b).first != a.end()) << endl;
            vector<int> a2 = {0, 1, 2, 3, 4, 5};
            list<int> b2 = {4, 2, 1, 5, 0, 3};
            auto match = neighbors_match(a2, b2);
            cout << boolalpha << distance(a2.cbegin(), match.first)
                 << ' ' << distance(b2.cbegin(), match.second) << endl;
            return 0;
        }
    

    【讨论】:

    • 我喜欢这适用于不同类型的容器 - 但你说得对,它确实让它变得非常罗嗦!
    【解决方案7】:

    您实质上要问的是两个面的边集(我们称它们为ab)是否不相交。这可以分解为b中的任何一条边是否在a中的问题,这只是一个隶属度测试。那么问题是向量在成员资格测试方面并不出色。

    我的解决方案是将其中一个向量转换为unordered_set&lt; pair&lt;int, int&gt; &gt;unordered_set 只是一个哈希表,对表示边。

    在表示边时,我采用了一种标准化方案,其中顶点的索引按递增顺序排列(因此 [2,1][1,2] 都在我的边集中存储为 [1,2])。这使得相等性测试更容易一些(因为它只是对的相等性)

    所以这是我的解决方案:

    #include <iostream>
    #include <utility>
    #include <functional>
    #include <vector>
    #include <unordered_set>
    using namespace std;
    
    using uint = unsigned int;
    using pii = pair<int,int>;
    
    // Simple hashing for pairs of integers
    struct pii_hash {
        inline size_t
        operator()(const pii & p) const
        {
            return p.first ^ p.second;
        }
    };
    
    // Order pairs of integers so the smallest number is first
    pii ord_pii(int x, int y) { return x < y ? pii(x, y) : pii(y, x); }
    
    bool
    shares_edge(vector<int> a, vector<int> b)
    {
        unordered_set<pii, pii_hash> edge_set {};
    
        // Create unordered set of pairs (the Edge Set)
        for(uint i = 0; i < a.size() - 1; ++i)
            edge_set.emplace( ord_pii(a[i], a[i+1]) );
    
        // Check if any edges in B are in the Edge Set of A
        for(uint i = 0; i < b.size() - i; ++i)
        {
            pii edge( ord_pii(b[i], b[i+1]) );
    
            if( edge_set.find(edge) != edge_set.end() )
                return true;
        }
    
        return false;
    }
    
    int main() {
        vector<int>
            a {0, 1, 2, 3, 4, 5},
            b {1, 4, 2, 0, 5, 3},
            c {4, 2, 1, 0, 5, 3};
    
        shares_edge(a, b); // false
        shares_edge(a, c); // true
    
        return 0;
    }
    

    在您的特定情况下,您可能希望将shares_edge 设为Face 类的成员函数。预先计算边缘集并将其存储为Face 的实例变量也可能是有益的,但这取决于边缘数据更改的频率与计算发生的频率。

    编辑额外解决方案

    EDIT 2 修正问题更改:边缘集现在环绕点列表。

    如果您添加边缘集,在初始化时预先计算到某种Face 类,这就是它的样子。私有嵌套的Edge 类可以被认为是用一个实际的类来装饰你当前对一条边的表示(即点列表中的两个相邻位置),因此集合之类的集合可以将点列表中的索引视为实际边缘:

    #include <cassert>
    #include <iostream>
    #include <utility>
    #include <functional>
    #include <vector>
    #include <unordered_set>
    
    using uint = unsigned int;
    
    class Face {
        struct Edge {
            int  _index;
            const std::vector<int> *_vertList;
    
            Edge(int index, const std::vector<int> *vertList)
                : _index {index}
                , _vertList {vertList}
            {};
    
            bool
            operator==(const Edge & other) const
            {
                return
                    ( elem() == other.elem() && next() == other.next() ) ||
                    ( elem() == other.next() && next() == other.elem() );
            }
    
            struct hash {
                inline size_t
                operator()(const Edge & e) const
                {
                    return e.elem() ^ e.next();
                }
            };
    
        private:
            inline int elem() const { return _vertList->at(_index); }
    
            inline int
            next() const
            {
                return _vertList->at( (_index + 1) % _vertList->size() );
            }
        };
    
        std::vector<int>                     _vertList;
        std::unordered_set<Edge, Edge::hash> _edgeSet;
    
    public:
    
        Face(std::initializer_list<int> verts)
            : _vertList {verts}
            , _edgeSet {}
        {
            for(uint i = 0; i < _vertList.size(); ++i)
                _edgeSet.emplace( Edge(i, &_vertList) );
        }
    
        bool
        shares_edge(const Face & that) const
        {
            for(const Edge & e : that._edgeSet)
                if( _edgeSet.find(e) != _edgeSet.end() )
                    return true;
    
            return false;
        }
    
    };
    
    int main() {
    
        Face
            a {0, 1, 2, 3, 4, 5},
            b {1, 4, 2, 0, 5, 3},
            c {4, 2, 1, 0, 5, 3},
            d {0, 1, 2, 3, 4, 6},
            e {4, 8, 6, 2, 1, 5, 0, 3};
    
        assert( !d.shares_edge(b) );
        assert(  a.shares_edge(b) );
        assert(  a.shares_edge(c) );
        assert(  a.shares_edge(e) );
    
        return 0;
    }
    

    如您所见,这种添加的抽象使得shares_edge() 的实现非常令人愉悦,但这是因为真正的技巧在于Edge 类的定义(或者更具体地说,@987654339 的关系) @)。

    【讨论】:

    • 这很酷。在我的应用程序中,我从“面”创建 3D 多面体,这些面是从“点”创建的。我可以在这个系统中添加“边缘”并创建成员函数来比较相等性,这可能是最简洁的解决方案 - 但我认为按顺序存储点就足够了。感谢您的回复!
    • 您无需明确添加Edges。 Face 类可以在初始化时生成它的边缘集,同时仍然保持对点的有序列表的引用(我意识到,这对于实际的绘图命令很有用)。除了点列表之外,我还为我的答案添加了一个额外的解决方案,它将边缘集添加到 Face 类中。
    【解决方案8】:

    首先,编写一个make_paired_range_view,它接受一个范围并返回一个范围,其迭代器返回std::tie( *it, *std::next(it) )boost 可以在这里提供帮助,因为他们编写的迭代器代码让这变得不那么烦人了。

    接下来,unordered_equal 接受两个 pairs 并忽略顺序比较它们(因此如果第一个相等,第二个相等,或者如果第一个等于另一个,则它们相等,反之亦然)。

    现在我们使用unordered_equal在右侧查找左侧的每一对。

    这样的好处是占用了 0 额外的内存,但缺点是 O(n^2) 时间。

    如果我们更关心时间而不是内存,我们可以将上面的pairs 在排序pair 之后按规范顺序将unordered_set 推入unordered_set。然后我们通过第二个容器,测试每一对(排序后),看看它是否在unordered_set 中。这需要O(n) 额外的内存,但在O(n) 时间内运行。它也可以在没有花哨的向量和范围写入的情况下完成。

    如果元素比int 更昂贵,您可以编写一个自定义的pseudo_pair 来保存指针,其哈希和相等性基于指针的内容。

    【讨论】:

    • +1 表示 pair 和 unordered_set 方法。不过,对于应该是一个简单算法的东西,它最终是很多抽象。
    【解决方案9】:

    一个有趣的“你会怎么做...”问题... :-) 它让我从在表单上的编辑框和组合框上抽出 15 分钟的休息时间,并进行一些编程以进行更改。 ..大声笑

    所以,我认为我会这样做......

    首先,我将边的概念定义为一对值(一对整数 - 遵循您的原始示例)。我意识到您的示例只是一个简化,您实际上使用的是您自己的类的向量(Point* 而不是 int?)但是模板化此代码并使用您想要的任何类型应该是微不足道的......

    #include <stdlib.h>
    #include <iostream>
    #include <vector>
    #include <set>
    #include <vector>
    using namespace std;
    
    typedef pair<int, int> edge;
    

    然后我会创建一个集合类,它将保持它的元素(边)以我们需要的方式排序(通过以不敏感的方式比较边 - 即如果 e1.first==e2.first 和 e1.second== e2.second 那么边 e1 和 e2 相同,但如果 e1.first==e2.second 和 e1.second==e2.first 则它们也相同)。为此,我们可以创建一个函数:

    struct order_insensitive_pair_less
    {
        bool operator() (const edge& e1, const edge& e2) const
        {
            if(min(e1.first,e1.second)<min(e2.first,e2.second)) return true;
            else if(min(e1.first,e1.second)>min(e2.first,e2.second)) return false;
            else return(max(e1.first,e1.second)<max(e2.first,e2.second));
        }
    };
    

    最后,我们的辅助类(称为 edge_set)将是使用上述函数排序的集合的简单派生,并添加了几个便利方法 - 一个构造函数,它从向量(或实际中的 Face 类)填充集合) 和一个测试函数 (bool share_edge(const vector&v)),它告诉我们该集合是否与另一个共享边。所以:

    struct edge_set : public set<edge, order_insensitive_pair_less>
    {
        edge_set(const vector<int>&v);
        bool shares_edge(const vector<int>&v);
    };
    

    实现为:

    edge_set::edge_set(const std::vector<int>&v) : set<edge, order_insensitive_pair_less>()
    {
        if(v.size()<2) return; // assume there must be at least 2 elements in the vector since it is supposed to be a list of edges...
        for (std::vector<int>::const_iterator it = v.begin()+1; it != v.end(); it++)
            insert(edge(*(it-1), *it));
    }
    
    bool edge_set::shares_edge(const std::vector<int>& v)
    {
        edge_set es(v);
        for(iterator es_it = begin(); es_it != end(); es_it++)
            if(es.count(*es_it))
                return true;
        return false;
    }
    

    然后使用变得微不足道(并且相当优雅)。假设您有两个向量作为变量 v1 和 v2 的问题摘要中的示例,以测试它们是否共享一条边,您只需编写:

    if(edge_set(v1).shares_edge(v2))
        // Yup, they share an edge, do something about it...
    else
        // Nope, not these two... Do something different...
    

    关于这种方法中元素数量的唯一假设是每个向量至少有 2 个(因为你不能有一个“边”没有至少到顶点)。但是,即使不是这种情况(其中一个向量是空的或只有一个元素) - 这将导致一个空的 edge_set 因此您只会得到一个答案,即它们没有共享边(因为其中一个集合是空的)。没什么大不了的...在我看来,这样做肯定会通过“两周测试”,因为您将有一个专门的课程,您可以在其中有几行评论来说明它在做什么,并且实际比较很漂亮可读 (edge_set(v1).shares_edge(v2))...

    【讨论】:

    • 一个非常详细的答案,我很感激。如果我从代码中的多个位置调用它,我可能会像你一样将它拆分,以便我可以使用简单的函数调用。但是,由于这是我只会在一个子例程中执行的操作,因此我试图避免过度抽象并使其保持一致。
    【解决方案10】:

    我知道我对此有点晚了,但这是我的看法:

    不在现场:

    #include <algorithm>
    #include <iostream>
    #include <tuple>
    #include <vector>
    
    template<typename Pair>
    class pair_generator {
    public:
        explicit pair_generator(std::vector<Pair>& cont)
        : cont_(cont)
        { }
    
        template<typename T>
        bool operator()(T l, T r) {
            cont_.emplace_back(r, l);
            return true;
        }
    private:
        std::vector<Pair>& cont_;
    };
    
    template<typename Pair>
    struct position_independant_compare {
    
        explicit position_independant_compare(const Pair& pair)
        : pair_(pair)
        { }
    
        bool operator()(const Pair & p) const {
            return (p.first == pair_.first && p.second == pair_.second) || (p.first == pair_.second && p.second == pair_.first);
        }
    private:
        const Pair& pair_;
    };
    
    template<typename T>
    using pair_of = std::pair<T, T>;
    
    template<typename T>
    std::ostream & operator <<(std::ostream & stream, const pair_of<T>& pair) {
        return stream << '[' << pair.first << ", " << pair.second << ']';
    }
    
    int main() {
        std::vector<int>
            v1 {0 ,1, 2, 3, 4, 5},
            v2 {4, 8, 6, 2, 1, 5, 0, 3};
    
        std::vector<pair_of<int> >
            p1 { },
            p2 { };
    
        // generate our pairs
        std::sort(v1.begin(), v1.end(), pair_generator<pair_of<int>>{ p1 });
        std::sort(v2.begin(), v2.end(), pair_generator<pair_of<int>>{ p2 });
    
        // account for the fact that the first and last element are a pair too
        p1.emplace_back(p1.front().first, p1.back().second);
        p2.emplace_back(p2.front().first, p2.back().second);
    
        std::cout << "pairs for vector 1" << std::endl;
        for(const auto & p : p1) { std::cout << p << std::endl; }
    
        std::cout << std::endl << "pairs for vector 2" << std::endl;
        for(const auto & p : p2) { std::cout << p << std::endl; }
    
        std::cout << std::endl << "pairs shared between vector 1 and vector 2" << std::endl;
        for(const auto & p : p1) {
            const auto pos = std::find_if(p2.begin(), p2.end(), position_independant_compare<pair_of<int>>{ p });
            if(pos != p2.end()) {
                std::cout << p << std::endl;
            }
        }
    }
    

    ideone 上的示例输出

    现场:

    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <tuple>
    #include <vector>
    
    template<typename T>
    struct in_situ_pair
    : std::iterator<std::forward_iterator_tag, T> {
    
        using pair = std::pair<T, T>;
    
        in_situ_pair(std::vector<T>& cont, std::size_t idx)
        : cont_(cont), index_{ idx }
        { }
    
        pair operator*() const {
            return { cont_[index_], cont_[(index_ + 1) % cont_.size()] };
        }
    
        in_situ_pair& operator++() {
            ++index_;
            return *this;
        }
    
        bool operator==(const pair& r) const {
            const pair l = operator*();
            return  (l.first == r.first && l.second == r.second)
                    || (l.first == r.second && l.second == r.first);
        }
    
        bool operator==(const in_situ_pair& o) const {
            return (index_ == o.index_);
        }
    
        bool operator!=(const in_situ_pair& o) const {
            return !(*this == o);
        }
    public:
        friend bool operator==(const pair& l, const in_situ_pair& r) {
            return (r == l);
        }
    private:
        std::vector<T>& cont_;
        std::size_t index_;
    };
    
    template<typename T>
    using pair_of = std::pair<T, T>;
    
    template<typename T>
    std::ostream & operator <<(std::ostream & stream, const pair_of<T>& pair) {
        return stream << '[' << pair.first << ", " << pair.second << ']';
    }
    
    namespace in_situ {
        template<typename T>
        in_situ_pair<T> begin(std::vector<T>& cont) { return { cont, 0 }; }
    
        template<typename T>
        in_situ_pair<T> end(std::vector<T>& cont) { return { cont, cont.size() }; }
    
        template<typename T>
        in_situ_pair<T> at(std::vector<T>& cont, std::size_t i) { return { cont, i }; }
    }
    
    int main() {
        std::vector<int>
            v1 {0 ,1, 2, 3, 4, 5},
            v2 {4, 8, 6, 2, 1, 5, 0, 3};
    
        for(std::size_t i = 0; i < v1.size(); ++i) {
            auto pos = std::find(in_situ::begin(v2), in_situ::end(v2), in_situ::at(v1, i));
            if(pos != in_situ::end(v2)) {
                std::cout << "common: " << *pos << std::endl;
            }
        }
    }
    

    ideone 上的示例输出

    【讨论】:

      【解决方案11】:

      我认为这是我能想到的最简洁的。

      bool check_for_pairs(std::vector<int> A, std::vector<int> B) {
        auto lastA = A.back();
        for (auto a : A) {
          auto lastB = B.back();
          for (auto b : B) {
            if ((b == a && lastB == lastA) || (b == lastA && lastB == a)) return true;
            lastB = b;
          }
          lastA = a;
        }
        return false;
      }
      

      更省时的方法是使用集合

      bool check_for_pairs2(std::vector<int> A, std::vector<int> B) {
        using pair = std::pair<int,int>;
        std::unordered_set< pair, boost::hash<pair> > lookup;
        auto last = A.back();
        for (auto a : A) {
          lookup.insert(a < last ? std::make_pair(a,last) : std::make_pair(last,a));
          last = a;
        }
        last = B.back();
        for (auto b : B) {
          if (lookup.count(b < last ? std::make_pair(b,last) : std::make_pair(last,b)))
            return true;
          last = b;
        }
        return false;
      }
      

      如果你实现了一个散列函数,将 (a,b) 和 (b,a) 散列到相同的值,你可以取消对哪个值最小的检查

      【讨论】:

        【解决方案12】:

        已经有很多很好的答案,我相信寻找在两个向量中寻找相邻相等元素对的一般问题的人会发现它们很有启发性。我决定回答我自己的问题,因为我认为我最初尝试的更简洁的版本是对我来说的最佳答案。

        由于似乎没有使方法更简单的标准算法组合,我相信循环和查询每个元素是最简洁和易于理解的。

        这是一般情况的算法:

        std::vector<int> vec1 = { 1, 2, 3, 4, 5, 6 };
        std::vector<int> vec2 = { 3, 1, 4, 2, 6, 5 };
        
        // Loop over the elements in the first vector, looking for an equal element in the 2nd vector
        for(int i = 0; i < vec1.size(); i++) for(int j = 0; j < vec2.size(); j++)
            if ( vec1[i] == vec2[j] &&
                // ... Found equal elements, now check if the next element matches the next or previous element in the other vector
                ( vec1[(i+1) % vec1.size()] == vec2[(j+1) % vec2.size()]
                ||vec1[(i+1) % vec1.size()] == vec2[(j-1+vec2.size()) % vec2.size()] ) )
                return true;
        return false;
        

        或者在我的特定情况下,我实际上是在检查向量的向量,其中元素不再是整数,而是指向类的指针。

        (Face类的operator[]返回一个属于人脸的向量元素)。

        bool isSurrounded(std::vector<Face*> * neighbours)
        {
            // We can check if each edge aligns with an edge in a nearby face,
            // ... if each edge aligns, then the face is surrounded
            // ... an edge is defined by two adjacent points in the points_ vector
            // ... so we check for two consecutive points to be equal...
            int count = 0;
            // for each potential face that is not this face
            for(auto&& i : *neighbours) if (i != this)
                // ... loop over both vectors looking for an equal point
                for (int j = 0; j < nPoints(); j++) for (int k = 0; k < i->nPoints(); k++ )
                    if ( (*this)[j] == (*i)[k] &&
                        // ... equal points have been found, check if the next or previous points also match
                       (  (*this)[(j+1) % nPoints()] == (*i)[(k+1) % i->nPoints()]
                       || (*this)[(j+1) % nPoints()] == (*i)[(k-1+i->nPoints()) % i->nPoints()] ) )
                       // ... an edge is shared
                        { count++; }
            // number of egdes = nPoints -1
            if (count > nPoints() - 1)
                return true;
            else
                return false;
        }
        

        【讨论】:

          猜你喜欢
          • 2018-03-31
          • 1970-01-01
          • 2010-12-13
          • 1970-01-01
          • 1970-01-01
          • 2013-05-23
          • 1970-01-01
          • 2013-05-03
          • 1970-01-01
          相关资源
          最近更新 更多