【问题标题】:Concatenate multiple std::vectors taking duplicates into account in c++17在 c++17 中连接多个 std::vectors 并考虑重复项
【发布时间】:2021-02-02 14:27:03
【问题描述】:

尽管在 C++ 中连接两个 std::vectors 很简单,尤其是对于范围,但我遇到了一个稍微不同的问题。

假设我有以下向量:{1,2,6}{6, 8, 9}{9, 8, 10} 等等。如果一个向量的尾部与连接到的下一个向量的头部相同,我希望最终向量中只有一个元素,如下所示:

conc({1,2,6}, {6,8,9}, {9,8,10}, {0, 1}) = {1,2,6,8,9,8,10,0,1}

我可以使用if 条件来做到这一点,但我认为它效率不高,因为我必须这样做数十万次,最好使用 STL 而没有外部库。

如果有帮助,总是只有 4 个向量需要连接。

编辑:被连接的向量的末尾和开头可能有也可能没有相同的元素。

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> v1{1,2,6};
    std::vector<int> v2{6,8,9};
    std::vector<int> v3{9,8,10};
    std::vector<int> v4{0, 1};

    std::vector<int>V{v1};
     
    

    if (v1.back() == v2.front())
    {
        for(auto it= v2.begin()+1; it != v2.end(); ++it)
        {
            V.push_back(*it);
        }
    }
    else
    {
         for(auto it= v2.begin(); it != v2.end(); ++it)
        {
            V.push_back(*it);
        }
    }

    //repeat the above prcess for other vectors
    
}

【问题讨论】:

  • 请出示您的代码。你忘了问一个问题。您正在寻找标准算法?
  • @Morpheus 这些向量 {9,8,10}, {0, 1} 是如何连接的?
  • @VladfromMoscow 把它们放在一起{9,8,10,0,1}
  • 您是否只是认为它效率低下,或者您是否真的测量您的这部分代码大大减慢了您的程序,以至于它可能值得改进吗?人们经常担心性能问题。
  • 我正在回家的路上。我会尽快发布代码。

标签: c++ vector concatenation


【解决方案1】:

您可以执行以下操作。

#include <iostream>
#include <vector>
#include <iterator>

int main() 
{
    std::vector<int> v1 = {1,2,6}, v2 = {6,8,9}, v3 = {9,8,10}, v4 = {0, 1};
    
    for ( auto p : { &v2, &v3, &v4 } )
    {
        auto it = std::begin( *p );

        if ( v1.back() == p->front() )
        {
            std::advance( it, 1 );
        }           

        v1.insert( std::end( v1 ), it, std::end( *p ) );
    }
    
    for ( const auto &item : v1 )
    {
        std::cout << item << ' ';
    }
    std::cout << '\n';
    
    return 0;
}

程序输出是

1 2 6 8 9 8 10 0 1

或者您可以在向量 v1 中预先预留足够的空间。例如

#include <iostream>
#include <vector>
#include <iterator>

int main() 
{
    std::vector<int> v1 = {1,2,6}, v2 = {6,8,9}, v3 = {9,8,10}, v4 = {0, 1};
    
    std::vector<int>::size_type n = v1.size();
    auto last = v1.back();
    
    for ( auto p : { &v2, &v3, &v4 } )
    {
        n += last == p->front() ? p->size() - 1 : p->size();
        last = p->back();
    }
    
    v1.reserve( n );
    
    for ( auto p : { &v2, &v3, &v4 } )
    {
        auto it = std::begin( *p );

        if ( v1.back() == p->front() )
        {
            std::advance( it, 1 );
        }           

        v1.insert( std::end( v1 ), it, std::end( *p ) );
    }
    
    for ( const auto &item : v1 )
    {
        std::cout << item << ' ';
    }
    std::cout << '\n';
    
    return 0;
}

【讨论】:

  • 我确实添加了我的代码,但你的代码看起来比我的优雅得多。
  • 我应该添加我不想破坏 v1、v2、v3 或 v4 的信息。但我可以从这里拿走。非常感谢!
  • @Morpheus 只需声明一个新向量,并在基于范围的 for 循环中包含元素 &v1。
  • 对于n += ,我可能只是std::accumulate 的尺寸,如果它太高了~2,谁在乎呢?
  • @Morpheus 这是我的个人风格。我相信它会使程序更具可读性。
【解决方案2】:

另一种解决方案是使用辅助容器,例如std::deque

#include <iostream>
#include <deque>
#include <vector>

std::vector<int> concat(const std::vector<std::vector<int>>& v2d)
{
    std::deque<int> sDeque;
    for (auto& v : v2d)
    {
        for (auto v2 : v)
        {
            if (sDeque.empty())
                sDeque.push_front(v2);
            else
            if ( sDeque.front() != v2 )
                sDeque.push_front(v2);
        }
    }
    return { sDeque.rbegin(), sDeque.rend() };
}

int main()
{
    auto v = concat({ {1,2,6}, {6,8,9}, {9,8,10}, {0, 1} });
    for (auto i : v)
        std::cout << i << " ";
}

输出:

1 2 6 8 9 8 10 0 1 

【讨论】:

    猜你喜欢
    • 2010-09-17
    • 2015-04-17
    • 2018-02-25
    • 1970-01-01
    • 2021-10-26
    • 1970-01-01
    相关资源
    最近更新 更多