1.3.33

1.3.33 #

解答 #

动态数组这里要注意 first 不要小于零。

代码 #

Deque 类 #

/// <summary>
/// 双端队列。
/// </summary>
/// <typeparam name="TItem">队列中要存放的元素。</typeparam>
public class Deque<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 _count;

    /// <summary>
    /// 默认构造函数,建立一个双端队列。
    /// </summary>
    public Deque()
    {
        _first = null;
        _last = null;
        _count = 0;
    }

    /// <summary>
    /// 检查队列是否为空。
    /// </summary>
    /// <returns></returns>
    public bool IsEmpty()
    {
        return _count == 0;
    }

    /// <summary>
    /// 返回队列中元素的数量。
    /// </summary>
    /// <returns></returns>
    public int Size()
    {
        return _count;
    }

    /// <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;
        }
        _count++;
    }

    /// <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;
        }
        _count++;
    }

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

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

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

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

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

        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;
        }
    }
}

ResizingArrayDeque 类 #

/// <summary>
/// 可自动扩容的双端队列。
/// </summary>
/// <typeparam name="TItem">队列中要存放的元素。</typeparam>
public class ResizingArrayDeque<TItem> : IEnumerable<TItem>
{
    private TItem[] _deque;
    private int _first;
    private int _last;
    private int _count;

    /// <summary>
    /// 默认构造函数,建立一个双向队列。
    /// </summary>
    public ResizingArrayDeque()
    {
        _deque = new TItem[2];
        _first = 0;
        _last = 0;
        _count = 0;
    }

    /// <summary>
    /// 检查队列是否为空。
    /// </summary>
    /// <returns></returns>
    public bool IsEmpty()
    {
        return _count == 0;
    }

    /// <summary>
    /// 返回队列中元素的数量。
    /// </summary>
    /// <returns></returns>
    public int Size()
    {
        return _count;
    }

    /// <summary>
    /// 为队列重新分配空间。
    /// </summary>
    /// <param name="capacity">需要重新分配的空间大小。</param>
    private void Resize(int capacity)
    {
        if (capacity <= 0)
            throw new ArgumentException();

        var temp = new TItem[capacity];
        for (var i = 0; i < _count; i++)
        {
            temp[i] = _deque[(_first + i) % _deque.Length];
        }
        _deque = temp;
        _first = 0;
        _last = _count;
    }


    /// <summary>
    /// 在队列左侧添加一个元素。
    /// </summary>
    /// <param name="item">要添加的元素</param>
    public void PushLeft(TItem item)
    {
        if (_count == _deque.Length)
        {
            Resize(2 * _count);
        }

        _first--;
        if (_first < 0)
        {
            _first += _deque.Length;
        }
        _deque[_first] = item;
        _count++;
    }

    public void PushRight (TItem item)
    {
        if (_count == _deque.Length)
        {
            Resize(2 * _count);
        }

        _deque[_last] = item;
        _last = (_last + 1) % _deque.Length;
        _count++;
    }

    public TItem PopRight()
    {
        if (IsEmpty())
        {
            throw new InvalidOperationException();
        }

        _last--;
        if (_last < 0)
        {
            _last += _deque.Length;
        }
        var temp = _deque[_last];
        _count--;
        if (_count > 0 && _count == _deque.Length / 4)
            Resize(_deque.Length / 2);
        return temp;
    }

    public TItem PopLeft()
    {
        if (IsEmpty())
            throw new ArgumentException();

        var temp = _deque[_first];
        _first = (_first + 1) % _deque.Length;
        _count--;
        if (_count > 0 && _count == _deque.Length / 4)
        {
            Resize(_deque.Length / 2);
        }
        return temp;
    }

    public IEnumerator<TItem> GetEnumerator()
    {
        return new ResizingDequeEnumerator(_deque, _first, _count);
    }

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

    private class ResizingDequeEnumerator : IEnumerator<TItem>
    {
        private TItem[] _deque;
        private int _current;
        private readonly int _first;
        private readonly int _count;

        public ResizingDequeEnumerator(TItem[] deque, int first, int count)
        {
            _deque = deque;
            _first = first;
            _count = count;
            _current = -1;
        }

        TItem IEnumerator<TItem>.Current => _deque[(_first + _current) % _deque.Length];

        object IEnumerator.Current => _deque[(_first + _current) % _deque.Length];

        void IDisposable.Dispose()
        {
            _deque = null;
            _current = -1;
        }

        bool IEnumerator.MoveNext()
        {
            if (_current == _count - 1)
            {
                return false;
            }

            _current++;
            return true;
        }

        void IEnumerator.Reset()
        {
            _current = -1;
        }
    }
}

Program.cs #

var a = new Deque<string>();
var b = new ResizingArrayDeque<string>();

a.PushLeft("first");
b.PushLeft("first");
a.PushRight("second");
b.PushRight("second");
Display(a, b);

a.PopLeft();
b.PopLeft();
Display(a, b);
a.PopRight();
b.PopRight();
Display(a, b);

static void Display(Deque<string> a, ResizingArrayDeque<string> b)
{
    foreach (var s in a)
    {
        Console.Write(s + " ");
    }

    Console.WriteLine();
    foreach (var s in b)
    {
        Console.Write(s + " ");
    }

    Console.WriteLine();
    Console.WriteLine();
}