我需要将std::vector
复制到std::stack
。
遍历向量并推入堆栈只是方法吗?
如果还有另一种方式,从绩效的角度来看,更好的选择是什么?
代码:
std::stack<A> m_stack;
std::vector<A> m_vec;
for (auto& elem : m_vec)
{
m_stack.push(elem);
}
答案 0 :(得分:12)
由于堆栈是容器适配器,您可以从基础容器创建堆栈:
std::vector<A> m_vec = /* ... */;
std::stack<A, std::vector<A>> m_stack(m_vec);
或者,如果您希望您的堆栈为deque
- 支持:
std::stack<A> m_stack(std::deque<A>(m_vec.begin(), m_vec.end()));
答案 1 :(得分:1)
堆栈的一些乐趣,展示了从另一个容器中将值放到堆栈上的各种方法。
假设我们为:
提供了合适的定义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;
}
答案 2 :(得分:1)
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());
}
答案 3 :(得分:0)
有关允许std::copy
在堆栈上使用的方法,请参阅this question,但开箱即用,没有比调用推送的循环更明显的方法。
至于表现,唯一的方法是衡量它。 (首先是代码的清晰度和正确性,然后担心速度。)