【问题标题】:Copy elements from std::vector into std::stack c++将元素从 std::vector 复制到 std::stack c++
【发布时间】:2016-03-30 21:20:36
【问题描述】:

我需要将std::vector 复制到std::stack

  1. 是不是遍历vector,压栈才是唯一的办法?

  2. 如果有其他方法,从性能的角度来看,什么是更好的选择?

代码:

 std::stack<A>   m_stack;
 std::vector<A>  m_vec;

 for (auto& elem : m_vec)
 {
    m_stack.push(elem);
 }

【问题讨论】:

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


    【解决方案1】:

    由于堆栈是容器适配器,您可以从底层容器创建堆栈:

    std::vector<A> m_vec = /* ... */;
    std::stack<A, std::vector<A>> m_stack(m_vec);
    

    或者,如果您希望您的堆栈支持deque-backed:

    std::stack<A> m_stack(std::deque<A>(m_vec.begin(), m_vec.end()));
    

    【讨论】:

    • 这里会发生复制吗?
    • @HumamHelfawi:是的。我认为 OP 想要那个,因为她说“我需要复制”。如果不再需要原件,也可以将矢量移入。
    • @KerrekSB 谢谢,我只是要求不要批评 :) 我在评论之前投了赞成票;)
    • @basav 为什么不呢? std::containers 与 std 库中的几乎所有其他内容一样具有移动感知能力
    • @TM:除了使用循环,或者可能派生自己的适配器并添加这样的工具之外,您无法做到这一点。检查the documentation 的(非常短的)界面以了解您可以做什么和不能做什么。如果账单不合适,不要费心使用堆栈,只需使用向量并堆栈一样操作它。不惜一切代价使用std::stack 是没有奖品的。
    【解决方案2】:

    一些有趣的堆栈展示了从另一个容器获取值到堆栈的各种方法。

    假设我们提供了适当的定义:

    template<class T, class Container>
    auto stack_pusher(std::stack<T, Container>& stack);
    

    我们可以这样写:

    int main()
    {
        using namespace std;
    
        // construct an initial vector
        vector<int> init { 7,6 };
    
        // construct a stack using a copy of the initial vector's elements
        // note that the stack's storage is automatically deduced
        stack<int> stack1 { { begin(init), end(init) } };
    
        // construct a stack directly from a container initialised with an initialiser list
        stack<int> stack2 { { 3,4,5 } };
    
        // another vector
        vector<int> myvector { 1, 2, 3, 4, 5, 6, 7, 8 };
    
        // copy vector onto stack using a forward iterator
        copy(begin(myvector),
             end(myvector),
             stack_pusher(stack1));
    
        // copy vector onto stack using a reverse iterator
        copy(rbegin(myvector),
             rend(myvector),
             stack_pusher(stack2));
    
        // display the stacks
        while (stack1.size() or stack2.size())
        {
            // function to encode an optional T as a string
            auto encode = [](const auto& opt)
            {
                return opt ? std::to_string(opt.value()) : std::string("*");
            };
    
            // function to pop a value from a stack if it's not empty.
            // return an optional
            auto maybe_pop = [](auto& stack)
            {
                using element_type = std::decay_t<decltype(stack.top())>;
                boost::optional<element_type> result;
                if (stack.size()) {
                    result = stack.top();
                    stack.pop();
                }
                return result;
            };
    
            cout
            << encode(maybe_pop(stack1))
            << "\t"
            << encode(maybe_pop(stack2)) << endl;
        }
    
        return 0;
    }
    

    输出将是:

    8       1
    7       2
    6       3
    5       4
    4       5
    3       6
    2       7
    1       8
    6       5
    7       4
    *       3
    

    这是完整的清单 (c++14):

    #include <iostream>
    #include <stack>
    #include <vector>
    #include <deque>
    #include <iterator>
    #include <utility>
    #include <boost/optional.hpp>
    
    // an iterator that pushes values onto a stack
    template<class Stack>
    struct push_iterator
    : std::iterator<std::output_iterator_tag,void,void,void,void>
    {
        push_iterator(Stack& stack)
        : pstack(std::addressof(stack))
        {}
    
        template<class T>
        auto& operator=(T&& t)
        {
            pstack->push(std::forward<T>(t));
            return *this;
        }
    
        auto& operator*() {
            return *this;
        }
    
        auto& operator++() {
            return *this;
        }
    
    private:
        Stack* pstack;
    };
    
    // convenience class to make a push_iterator of the correct type
    template<class T, class Container>
    auto stack_pusher(std::stack<T, Container>& stack)
    {
        return push_iterator<std::stack<T, Container>>(stack);
    }
    
    int main()
    {
        using namespace std;
    
        // construct an initial vector
        vector<int> init { 7,6 };
    
        // construct a stack using a copy of the initial vector's elements
        // note that the stack's storage is automatically deduced
        stack<int> stack1 { { begin(init), end(init) } };
    
        // construct a stack directly from a container initialises with an initialiser list
        stack<int> stack2 { { 3,4,5 } };
    
        // another vector
        vector<int> myvector { 1, 2, 3, 4, 5, 6, 7, 8 };
    
        // copy vector onto stack using a forward iterator
        copy(begin(myvector),
             end(myvector),
             stack_pusher(stack1));
    
        // copy vector onto stack using a reverse iterator
        copy(rbegin(myvector),
             rend(myvector),
             stack_pusher(stack2));
    
        // display the stacks
        while (stack1.size() or stack2.size())
        {
            // function to encode an optional T as a string
            auto encode = [](const auto& opt)
            {
                return opt ? std::to_string(opt.value()) : std::string("*");
            };
    
            // function to pop a value from a stack if it's not empty.
            // return an optional
            auto maybe_pop = [](auto& stack)
            {
                using element_type = std::decay_t<decltype(stack.top())>;
                boost::optional<element_type> result;
                if (stack.size()) {
                    result = stack.top();
                    stack.pop();
                }
                return result;
            };
    
            cout
            << encode(maybe_pop(stack1))
            << "\t"
            << encode(maybe_pop(stack2)) << endl;
        }
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      std::stack 是一个奇怪但可破解的容器:

      #include<vector>
      #include<stack>
      
      struct A{};
      
      template<class T>
      struct mystack : std::stack<T>{
          decltype(auto) c(){return std::stack<T>::c;}
      };
      
      int main(){
          std::vector<A>  m_vec;
      
          mystack<A>   m_stack;
          m_stack.c().assign(m_vec.begin(), m_vec.end());
      
      }
      

      #include<vector>
      #include<stack>
      
      struct A{};
      
      template<class... T>
      struct mystack : std::stack<T...>{
          decltype(auto) container(){return std::stack<T...>::c;}
      };
      
      template<class... T>
      decltype(auto) container(std::stack<T...>& s){return static_cast<mystack<T...>&>(s).container();}
      
      int main(){
          std::vector<A>  m_vec;
      
          std::stack<A>   m_stack;
          container(m_stack).assign(m_vec.begin(), m_vec.end());
      }
      

      【讨论】:

        【解决方案4】:

        请参阅 this question 了解允许在堆栈上使用 std::copy 的方法,但开箱即用,没有比调用 push 的循环更明显的方法了。

        至于性能,唯一的判断方法就是衡量它。 (代码首先要清晰和正确,然后担心速度。)

        【讨论】:

          猜你喜欢
          • 2011-05-19
          • 1970-01-01
          • 1970-01-01
          • 2012-09-11
          • 2011-02-23
          • 1970-01-01
          • 1970-01-01
          • 2014-01-11
          • 1970-01-01
          相关资源
          最近更新 更多