1.3.48

1.3.48 #

解答 #

按照双向队列原本的操作就可以实现,需要维护两个栈的长度以防越界。(左侧栈弹出了右侧栈栈底的内容)

代码 #

public class DeStack<TItem> : IEnumerable<TItem>
{
    private class DoubleNode<T>
    {
        public T Item;
        public DoubleNode<T> Next;
        public DoubleNode<T> Prev;
    }

    private DoubleNode<TItem> _first;
    private DoubleNode<TItem> _last;
    private int _leftCount;
    private int _rightCount;

    /// <summary>
    /// 默认构造函数,建立一个双端栈。
    /// </summary>
    public DeStack()
    {
        _first = null;
        _last = null;
        _leftCount = 0;
        _rightCount = 0;
    }

    /// <summary>
    /// 检查左侧栈是否为空。
    /// </summary>
    /// <returns></returns>
    public bool IsLeftEmpty()
    {
        return _leftCount == 0;
    }

    /// <summary>
    /// 检查右侧栈是否为空。
    /// </summary>
    /// <returns></returns>
    public bool IsRightEmpty()
    {
        return _rightCount == 0;
    }

    /// <summary>
    /// 返回左侧栈中元素的数量。
    /// </summary>
    /// <returns></returns>
    public int LeftSize()
    {
        return _leftCount;
    }

    /// <summary>
    /// 返回右侧栈中元素的数量。
    /// </summary>
    /// <returns></returns>
    public int RightSize()
    {
        return _rightCount;
    }

    /// <summary>
    /// 向左端添加一个元素。
    /// </summary>
    /// <param name="item">要添加的元素。</param>
    public void PushLeft(TItem item)
    {
        var oldFirst = _first;
        _first = new DoubleNode<TItem>
        {
            Item = item,
            Prev = null,
            Next = oldFirst
        };
        if (oldFirst == null)
        {
            _last = _first;
        }
        else
        {
            oldFirst.Prev = _first;
        }
        _leftCount++;
    }

    /// <summary>
    /// 向右端添加一个元素。
    /// </summary>
    /// <param name="item">要添加的元素。</param>
    public void PushRight(TItem item)
    {
        var oldLast = _last;
        _last = new DoubleNode<TItem>
        {
            Item = item,
            Prev = oldLast,
            Next = null
        };

        if (oldLast == null)
        {
            _first = _last;
        }
        else
        {
            oldLast.Next = _last;
        }
        _rightCount++;
    }

    /// <summary>
    /// 从右端删除并返回一个元素。
    /// </summary>
    /// <returns></returns>
    public TItem PopRight()
    {
        if (IsRightEmpty())
        {
            throw new InvalidOperationException();
        }

        var temp = _last.Item;
        _last = _last.Prev;
        _rightCount--;

        if (_last == null)
        {
            _first = null;
        }
        else
        {
            _last.Next.Item = default;
            _last.Next = null;
        }
        return temp;
    }

    /// <summary>
    /// 从左端删除并返回一个元素。
    /// </summary>
    /// <returns></returns>
    public TItem PopLeft()
    {
        if (IsLeftEmpty())
        {
            throw new InvalidOperationException();
        }

        var temp = _first.Item;
        _first = _first.Next;
        _leftCount--;

        if (_first == null)
        {
            _last = null;
        }
        else
        {
            _first.Prev.Item = default;
            _first.Prev = null;
        }

        return temp;
    }

    public IEnumerator<TItem> GetEnumerator()
    {
        return new DequeEnumerator(_first);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    private class DequeEnumerator : IEnumerator<TItem>
    {
        private DoubleNode<TItem> _current;
        private DoubleNode<TItem> _first;

        public DequeEnumerator(DoubleNode<TItem> first) 
        {
            _current = new DoubleNode<TItem>();
            _current.Next = first;
            _current.Prev = null;
            _first = _current;
        }

        public TItem Current => _current.Item;

        object IEnumerator.Current => _current.Item;

        public void Dispose()
        {
            _current = null;
            _first = null;
        }

        public bool MoveNext()
        {
            if (_current.Next == null)
                return false;
            _current = _current.Next;
            return true;
        }

        public void Reset()
        {
            _current = _first;
        }
    }
}