【问题标题】:How to traverse stack in C++?如何在 C++ 中遍历堆栈?
【发布时间】:2014-06-05 08:23:23
【问题描述】:

是否可以在 C++ 中遍历std::stack

使用以下方法遍历不适用。因为std::stack 没有成员end

std::stack<int> foo;

// ..

for (__typeof(foo.begin()) it = foo.begin(); it != foo.end();  it++)
{
    // ...
}

【问题讨论】:

  • 这就是为什么它是一个“堆栈”。后进先出,就是这样(理论上)。
  • 您选择了错误的数据类型。如果您希望能够对其进行迭代,请不要使用堆栈。

标签: c++ stack traversal


【解决方案1】:

认为可以遍历stack。我能想到的最好的方法是使用std::vector 使用push_back(), pop_back() 使用向量

堆栈不提供 begin 或 end 成员函数,因此您不能将它与需要两者的 range based for loop 一起使用。

在你的情况下,如果你真的想遍历它,最好选择其他一些数据结构。

【讨论】:

    【解决方案2】:

    C++可以遍历std::stack吗?

    没有。当您有兴趣将元素放在顶部并从顶部获取元素时,堆栈是您应该使用的数据结构。如果您想要一个可迭代的堆栈,请为堆栈角色使用不同的数据结构 (std::vector?) 或自己编写一个。

    【讨论】:

      【解决方案3】:

      我们无法遍历堆栈。堆栈是一种容器适配器,专门设计用于在 LIFO 上下文(后进先出)中运行,其中元素仅从容器的一端插入和提取。元素从特定容器的“后部”被推入/弹出,这被称为堆栈的顶部。堆栈不打算显示此行为,为此我们有其他容器

      【讨论】:

        【解决方案4】:
        #include <stack>
        
        using std::stack;    
        
        stack< int > numbers;
        numbers.push( 1 );
        numbers.push( 2 );
        
        while ( not numbers.empty( ) )
        {
            int number = numbers.top( );
            numbers.pop( );
        }
        

        http://en.cppreference.com/w/cpp/container/stack

        【讨论】:

        • 这会改变/清空堆栈。我最初想要的只是遍历堆栈并打印它以进行调试。
        【解决方案5】:

        正如您提到的,您需要打印以进行调试,也许这样的东西对您有用:

        // Example program
        #include <iostream>
        #include <string>
        #include <stack>
        #include <vector>
        #include <algorithm>
        
        template <typename T>
        void StackDebug(std::stack<T> s)
        {
            std::vector<T> debugVector = std::vector<T>();
            while (!s.empty( ) )
            {
                T t = s.top( );
                debugVector.push_back(t);
                s.pop( );
            }
        
            // stack, read from top down, is reversed relative to its creation (from bot to top)
            std::reverse(debugVector.begin(), debugVector.end());
            for(const auto& it : debugVector)
            {
                std::cout << it << " ";
            }
        }
        
        int main()
        {
        
            std::stack< int > numbers;
            numbers.push( 9 );
            numbers.push( 11 );
        
            StackDebug(numbers);
        }
        

        正如预期的那样,输出是“9 11”

        【讨论】:

        • 有人对此投了反对票,因为堆栈不应该像这样使用。但是您说这是出于调试目的,您是对的。开发人员必须在生产中正确行事,但有时为了测试需要打破一些默认行为。
        【解决方案6】:

        你可以做一个for循环:

        for (stack<T> newStack = stack; !newStack.empty(); newStack.pop()){
           T item = newStack.top();
        }
        

        【讨论】:

        • 我在这里看到一个语法错误!此外,OP 正在寻找一种不会弹出所有内容的解决方案。
        【解决方案7】:

        不可能直接遍历std:: stack,因为它没有end 成员,而堆栈数据结构应该是这样的,即只有一个指针。但是,这里仍然有两个懒惰的黑客来遍历它:

        1) 基于循环:

        while(!st.empty()) {
                cout << st.top();
                st.pop();
            }
        

        基于循环的方法的问题:

        • 原始堆栈变空。

        2) 基于递归:

        template <typename T>
        void traverse_stack(stack<T> & st) {
            if(st.empty())
                return;
            T x = st.top();
            cout << x << " ";
            st.pop();
            traverse_stack(st);
            st.push(x);
        }
        

        基于递归的方法的优点:

        • 维护原始堆栈元素。

        基于递归的方法的问题:

        • 维护一个内部堆栈。
        • 可能会因堆栈过大而失败。

        【讨论】:

        • 对于基于循环,您始终可以将要从原始堆栈弹出的元素推送到另一个堆栈。然后,一旦您完成迭代,将另一个堆栈排到您的原始堆栈上,保持原始状态。基本上用调用堆栈做你在基于递归的解决方案中所做的同样的事情。
        【解决方案8】:

        如果您想实现 LIFO 概念并能够同时进行迭代,请使用 std::deque。 要模拟堆栈,请使用 push_front()、front()、pop_front()

        https://en.cppreference.com/w/cpp/container/deque

        内部双端队列是“单独分配的固定大小数组”的序列,因此在处理大量数据时比堆栈好得多,但比向量差。

        【讨论】:

          【解决方案9】:

          人们可以在 STL 的 std::stack 上编写一个简单的包装器,然后遍历底层容器,因为引用 reference

          容器必须满足SequenceContainer的要求

          此容器可通过受保护成员 c 访问,因此this 之类的内容可能适合您的情况:

          #include <stack>
          #include <iostream>
          #include <iterator>
          
          template <typename T, typename Container = std::deque<T>>
          struct DebugStack : private std::stack<T, Container> {
              auto& push(T& elem) {
                  std::stack<T>::push(elem);
                  return *this;
              }
              auto& push(T&& elem) {
                  std::stack<T>::push(elem);
                  return *this;
              }
              auto& pop() {
                  std::stack<T>::pop();
                  return *this;
              }
              T top() {
                  return std::stack<T>::top();
              }
              void print() {
                  auto const& container = std::stack<T>::c;
                  //T should be printable
                  std::copy(begin(container), end(container), std::ostream_iterator<T>(std::cout, " "));
                  std::cout<<'\n';
              }
          };
          
          int main() {
              {
                  DebugStack<int> stack;
                  stack.push(1).push(2).push(3).push(4);
                  stack.print();
                  stack.pop().pop().pop();
                  stack.print();
              }
          
              {
                  DebugStack<std::string> stack;
                  stack.push("First").push("Second").push("Third").push("Fourth");
                  stack.print();
                  stack.pop().pop().pop();
                  stack.print();
              }
          }
          

          输出:

          1 2 3 4 
          1 
          First Second Third Fourth 
          First 
          

          可以将auto 返回类型更改为DebugStack(如here)以使此解决方案与C++11 一起使用,因为C++14 引入了返回类型的自动推导。

          【讨论】:

          • 这看起来很酷。最早的 C++ 版本是什么?
          • @user1857492 更新了我的答案以包含 C++ 版本信息。它可以与 C++11 一起工作而无需做太多改动。
          【解决方案10】:
                  stack<int> s,dbg; //s = not what's supposed to be
          
                  while(!s.empty()) {
                      cout << s.top() << " "; //print top of stack
                      dbg.push(s.top());      //push s.top() on a debug stack
                      s.pop();                //pop top off of s
                  }
          
                  //pop all elements of dbg back into stack as they were
                  while(!dbg.empty()) {
                      s.push(dbg.top());
                      dbg.pop();
                  }
          

          我只需要这样做来检查 Leetcode 问题中的堆栈到底出了什么问题。显然,在现实世界中,只使用调试器可能更有意义。

          【讨论】:

            【解决方案11】:

            我不会这样做,但是您可以在不使用指针转换弹出的情况下获得堆栈值,这对编译后的类如何存储在内存中做出了一些假设,一般来说不是一个好主意。

            只要不更改默认的底层容器std::deque,就可以:

            std::stack<int>s;
            s.push(1234);
            s.push(789);
            
            std::deque<int>* d;
            d = (std::deque<int>*)&s;
            cout << (*d)[0] << endl;
            cout << (*d)[1] << endl;
            

            在不弹出堆栈的情况下输出:

            1234
            789
            

            【讨论】:

              猜你喜欢
              • 2016-08-13
              • 1970-01-01
              • 2011-03-13
              • 2012-02-05
              • 1970-01-01
              • 2011-12-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多