【问题标题】:How to implement a stack with push and pop in Dart如何在 Dart 中使用 push 和 pop 实现堆栈
【发布时间】:2020-09-25 08:55:27
【问题描述】:

我想在 Dart 中实现一个堆栈数据结构(不要与 Flutter Stack 小部件混淆),以便我可以处理一堆自定义 TextStyles 以进行 Flutter 文本渲染。

我知道堆栈可以推送和弹出值。这听起来与 Queue 类似,但我不确定其中的区别。

这不起作用:

final myStack = Queue<int>();
myStack.push(1);
final top = myStack.pop();

【问题讨论】:

    标签: flutter dart stack queue


    【解决方案1】:

    堆栈是先进后出 (FILO) 数据结构。如果您制作一摞书,则您放下的第一本书将被您堆叠在其上的任何其他书所覆盖。而且,除非您删除上面的所有其他书,否则您无法取回该书。

    实施

    您可以通过多种不同的方式实现堆栈。此答案的原始版本(请参阅edit history)使用Queue 作为基础数据结构。但是,default Dart Queue itself uses a list,所以看起来List 是更直接的方法。下面是我现在实现堆栈的方式:

    class Stack<E> {
      final _list = <E>[];
    
      void push(E value) => _list.add(value);
    
      E pop() => _list.removeLast();
    
      E get peek => _list.last;
    
      bool get isEmpty => _list.isEmpty;
      bool get isNotEmpty => _list.isNotEmpty;
    
      @override
      String toString() => _list.toString();
    }
    

    注意事项

    • To push 表示将一个值添加到堆栈顶部。这是在此处使用 _list.add 实现的,这是一个快速 O(1) 操作。
    • To pop 表示从栈顶移除一个值。这是在此处使用 _list.removeLast 实现的,这是一个快速 O(1) 操作。
    • To peek 意味着获取堆栈中顶部元素的值而不实际删除它。这是在此处使用 _list.last 实现的,这是一个快速 O(1) 操作。

    可空实现

    使用上述堆栈实现时,您通常会在尝试poppeek 之前检查isNotEmpty,因为在空堆栈上这样做会导致底层List 抛出错误。但是,如果您更愿意检查 null,则可以将 poppeek 设为可空:

    E? pop() => (isEmpty) ? null : _list.removeLast();
    
    E? get peek => (isEmpty) ? null : _list.last;
    

    用法

    您可以像这样使用Stack

    void main() {
      final myStack = Stack<String>();
    
      myStack.push('Green Eggs and Ham');
      myStack.push('War and Peace');
      myStack.push('Moby Dick');
    
      while (myStack.isNotEmpty) {
        print(myStack.pop());
      }
    }
    

    这是输出:

    Moby Dick
    War and Peace
    Green Eggs and Ham
    

    【讨论】:

    • 在弹出窗口中,您可以通过将_stack.removeLast() 的返回值分配给lastElement 来简化弹出窗口(也可以只返回它,不带变量)
    • @L3n,是的,你是对的。现在制作堆栈时还有许多其他更改,所以我重写了整个答案。感谢您的评论。
    • 值得一提的是,默认的 Queue 实现使用的是列表而不是列表。它实际上使用 ListQueue。
    • @lig,如果您查看ListQueue 的实现,它使用List
    • @Suragch 我明白了,对。但是,有一些增长优化。基础列表不会经常增长,并且元素正在移动很多。因此,使用 Queue a Stack 似乎没有任何好处。列表可能会更快,因为涉及的逻辑更少。
    【解决方案2】:

    这是我使用的类

    import 'dart:collection';
    
    class Stack<T> {
      final _stack = Queue<T>();
    
      int get length => _stack.length;
    
      bool canPop() => _stack.isNotEmpty;
      
      void clearStack(){
        while(_stack.isNotEmpty){
          _stack.removeLast();
        }
      }
    
      void push(T element) {
        _stack.addLast(element);
      }
    
      T pop() {
        T lastElement = _stack.last;
        _stack.removeLast();
        return lastElement;
      }
    
      T peak() => _stack.last;
    
    }
    

    【讨论】:

      【解决方案3】:

      我的队列包装器版本:

      import "dart:collection" show Queue;
      
      class Stack<T> {
        final Queue<T> _underlyingQueue;
      
        Stack() : this._underlyingQueue = Queue<T>();
      
        int get length => this._underlyingQueue.length;
        bool get isEmpty => this._underlyingQueue.isEmpty;
        bool get isNotEmpty => this._underlyingQueue.isNotEmpty;
      
        void clear() => this._underlyingQueue.clear();
      
        T peek() {
          if (this.isEmpty) {
            throw StateError("Cannot peek() on empty stack.");
          }
          return this._underlyingQueue.last;
        }
      
        T pop() {
          if (this.isEmpty) {
            throw StateError("Cannot pop() on empty stack.");
          }
          return this._underlyingQueue.removeLast();
        }
      
        void push(final T element) => this._underlyingQueue.addLast(element);
      }
      

      【讨论】:

        【解决方案4】:

        我修改了其他答案的版本,以使用可为空的。

        import 'dart:collection';
        
        class StackCollection<T> {
          final _queue = Queue<T>();
        
          void push(T element) {
            _queue.addLast(element);
          }
        
          T? pop() {
            return this.isEmpty ? null : _queue.removeLast();
          }
        
          void clear() {
            _queue.clear();
          }
        
          bool get isEmpty => _queue.isEmpty;
          bool get isNotEmpty => _queue.isNotEmpty;
          int get length => this._queue.length;
        }
        

        也重命名为StackCollection,以避免Stack widget的干扰

        【讨论】:

          猜你喜欢
          • 2011-05-04
          • 2016-08-16
          • 2013-04-20
          • 2014-08-12
          • 2010-09-30
          • 2013-12-21
          • 2021-09-06
          • 1970-01-01
          • 2021-10-14
          相关资源
          最近更新 更多