java数据结构系列,第四篇:双端队列

双端队列(Double-ended queue,简称Deque)是一种数据结构,允许在队列的两端进行插入和删除操作。它可以被看作是一个允许元素插入和删除的线性表,但与普通队列不同,双端队列支持在队列的头部和尾部进行插入和删除操作,因此具有更加灵活的使用方式。

双端队列的特点包括:

  1. 前端插入和删除: 可以在双端队列的前端执行插入和删除操作。这使得双端队列可以像栈一样用于一些问题,比如实现逆序计算或其他需要后进先出(LIFO)操作的场景。

  2. 后端插入和删除: 同样可以在双端队列的后端执行插入和删除操作。这使得双端队列保持了队列的性质,即先进先出(FIFO)。

双端队列常见的操作包括:

  • 在前端插入元素(push_front):将一个新元素插入到双端队列的头部。
  • 在前端删除元素(pop_front):删除并返回双端队列的头部元素。
  • 在后端插入元素(push_back):将一个新元素插入到双端队列的尾部。
  • 在后端删除元素(pop_back):删除并返回双端队列的尾部元素。
  • 获取前端元素(front):返回双端队列的头部元素,但不进行删除。
  • 获取后端元素(back):返回双端队列的尾部元素,但不进行删除。

双端队列在很多算法和数据结构问题中都有广泛的应用,因为它的灵活性使得它可以同时满足栈和队列的需求。在编程中,许多编程语言提供了标准库中的双端队列实现,以方便开发者使用。

下面分别是用链表和数组实现双端队列:

先定义一个接口:
 

public interface Deque<E>
{
    /**
     * 从头部插入
     * @param e 要插入的元素
     * @return 是否插入成功
     */
    boolean offerFirst(E e);
    /**
     * 从尾部插入
     * @param e 要插入的元素
     * @return 是否插入成功
     */
    boolean offerLast(E e);
    /**
     * 从头部删除
     * @return 被删除的元素
     */
    E pollFirst();
    /**
     * 从尾部删除
     * @return 被删除的元素
     */
    E pollLast();
    /**
     * 从头部查看
     * @return 被查看的元素
     */
    E peekFirst();
    /**
     * 从尾部查看
     * @return 被查看的元素
     */
    E peekLast();
    /**
     * 队列是否为空
     * @return 是否为空
     */
    boolean isEmpty();
    /**
     * 队列是否已满
     * @return 是否已满
     */
    boolean isFull();
}

链表实现:



public class LinkedListDeque<E>  implements Deque<E>, Iterable<E>
{
    /**
     * 双向链表节点类
     * @param <E> 节点存储的元素类型
     */
    static class Node<E>
    {
        Node<E> prev;//前驱,表示当前节点的前一个节点
        E value;//值
        Node<E> next;//后继,当前节点的后一个节点
        Node(final Node<E> prev,final E value,final Node<E> next)
        {
            this.prev = prev;
            this.value = value;
            this.next = next;
        }
    }
    int capacity = Integer.MAX_VALUE;//容量
    int size;//当前元素个数
    Node<E> sentinel = new Node<>(null,null,null);//哨兵节点

        /**
         * 构造函数
         * @param capacity 容量
         */
    public LinkedListDeque(final int capacity)
    {
        this.capacity = capacity;
        sentinel.prev = sentinel;
        sentinel.next = sentinel;
    }
    /**
     * 构造函数
     */
    public LinkedListDeque()
    {
        sentinel.prev = sentinel;
        sentinel.next = sentinel;
    }

    /**
     * 迭代器
     * @return 迭代器
     */
    @Override
    public Iterator<E> iterator()
    {
        return new Iterator<E>() {
            Node<E> p = sentinel.next;//当前节点
            /**
             * 是否有下一个元素
             * @return 是否有下一个元素,p不等于哨兵节点时有下一个元素
             */
            @Override
            public boolean hasNext()
            {
                return p != sentinel;
            }
            
            /**
             * 获取当前元素的值,并将p指向下一个元素
             * @return 当前元素的值
             */

            @Override
            public E next()
            {
                E value = p.value;
                p = p.next;
                return value;
            }
        };
    }

    /**
     * 从头部插入
     * @param e 要插入的元素
     * @return 是否插入成功
     */
    @Override
    public boolean offerFirst(final E e)
    {
        if (isFull())
        {
            return false;
        }
        Node<E> a = sentinel;
        Node<E> b = sentinel.next;
        Node<E> added = new Node<>(a,e,b);
        a.next = added;
        b.prev = added;
        size ++;
        return true;
    }

    /**
     * 从尾部插入
     * @param e 要插入的元素
     * @return 是否插入成功
     */
    @Override
    public boolean offerLast(final E e)
    {
        if (isFull())
        {
            return false;
        }
        Node<E> a = sentinel.prev;
        Node<E> b = sentinel;
        Node<E> added = new Node<>(a,e,b);
        a.next = added;
        b.prev = added;
        size ++;
        return true;
    }

    /**
     * 从头部删除
     * @return 被删除的元素
     */
    @Override
    public E pollFirst()
    {
        if (isEmpty())
        {
            return null;
        }
        Node<E> a = sentinel;
        Node<E> removed = sentinel.next;
        Node<E> b = removed.next;
        a.next = b;
        b.prev = a;
        size --;
        return removed.value;
    }

    /**
     * 从尾部删除
     * @return 被删除的元素
     */
    @Override
    public E pollLast()
    {
        if (isEmpty())
        {
            return null;
        }
        Node<E> removed = sentinel.prev;
        Node<E> a = removed.prev;
        Node<E> b = sentinel;
        a.next = b;
        b.prev = a;
        size --;
        return removed.value;
    }

    /**
     * 从头部查看
     * @return 被查看的元素
     */
    @Override
    public E peekFirst()
    {
        if (isEmpty())
        {
            return null;
        }
        return sentinel.next.value;
    }

    /**
     * 从尾部查看
     * @return 被查看的元素
     */
    @Override
    public E peekLast()
    {
        if (isEmpty())
        {
            return null;
        }
        return sentinel.prev.value;
    }

    /**
     * 队列是否为空
     * @return 是否为空
     */
    @Override
    public boolean isEmpty()
    {
        return size == 0;
    }

    /**
     * 队列是否已满
     * @return 是否已满
     */
    @Override
    public boolean isFull()
    {
        return size == capacity;
    }
    
    
    /**
     * 重写toString方法
     */

    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        int i = 0;
        for (E e : this)
        {
            i ++;
            if (i == size)
            {
                sb.append(e);
            }
            else
            {
                sb.append(e);
                sb.append(",");
            }
        }
        sb.append("]");
        return sb.toString();
    }
}

数组实现:
 



public class ArrayDeque1<E> implements Iterable<E>, Deque<E>
{
    /**
     * 用于给数组下标加1,如果到达数组末尾则返回0
     * @param i 当前下标
     * @param length 数组长度
     * return i+1    下标加1
     */
    static int inc(int i,int length)
    {
        if (i + 1 >= length)
        {
            return 0;
        }
        return i + 1;
    }
    
    /**
     * 用于给数组下标减1,如果到达数组头部则返回数组末尾下标
     * @param i 当前下标
     * @param length 数组长度
     * return i-1    下标减1
     */
    static int dec(int i,int length)
    {
        if (i - 1 < 0)
        {
            return length - 1;
        }
        return i - 1;
    }

    E[] array;//数组
    int head;//头指针,代表该队列的第一个元素
    int tail;//尾指针,始终置空,不存储元素,只是用来标记下一次尾部插入时,元素插入的位置

    /**
     * 构造函数
     * @param capacity 容量
     */
    public ArrayDeque1(int capacity)
    {
        array = (E[]) new Object[capacity + 1];
    }
    
    /**
     * 实现迭代器
     */
    @Override
    public Iterator<E> iterator()
    {
        return new Iterator<E>() {
            int p = head;//当前指针
            /**
             * 是否有下一个元素
             * @return 是否有下一个元素,p不等于尾指针时有下一个元素
             */
            @Override
            public boolean hasNext() {
                return p != tail;
            }

            /**
             * 获取当前元素的值,并将p指向下一个元素
             * @return 当前元素的值
             */
            @Override
            public E next() {
                E value = array[p];
                p = inc(p,array.length);
                return value;
            }
        };
    }

    /**
     * 从头部插入
     * @param e 要插入的元素
     * @return 是否插入成功
     */
    @Override
    public boolean offerFirst(E e)
    {
        if (isFull())
        {
            return false;
        }
        head = dec(head,array.length);//头指针向前一步
        array[head] = e;//在当前头指针处插入元素
        return true;
    }

    /**
     * 从尾部插入
     * @param e 要插入的元素
     * @return 是否插入成功
     */
    @Override
    public boolean offerLast(E e)
    {
        if (isFull())
        {
            return false;
        }
        array[tail] = e;//在当前尾指针处插入元素
        tail = inc(tail,array.length);//尾指针向后一步
        return true;
    }

    /**
     * 从头部删除
     * @return 被删除的元素
     */
    @Override
    public E pollFirst()
    {
        if (isEmpty())
        {
            return null;
        }
        E e = array[head];
        array[head] = null;//清理内存,help GC
        head = inc(head,array.length);
        return e;
    }

    @Override
    public E pollLast()
    {
        if (isEmpty())
        {
            return null;
        }
        tail = dec(tail,array.length);
        E e = array[tail];
        array[tail] = null;//help GC
        return e;
    }

    /**
     * 从头部查看
     * @return 被查看的元素
     */
    @Override
    public E peekFirst()
    {
        if (isEmpty())
        {
            return null;
        }
        return array[head];
    }

    /**
     * 从尾部查看
     * @return 被查看的元素
     */
    @Override
    public E peekLast()
    {
        if (isEmpty())
        {
            return null;
        }
        return array[dec(tail,array.length)];
    }

    /**
     * 队列是否为空
     * @return 是否为空
     */
    @Override
    public boolean isEmpty()
    {
        return head == tail;
    }

    /**
     * 队列是否已满,两种情况:
     * 1.如果尾指针在头指针后面,则当尾指针减头指针等于数组长度减1时,队列已满
     * 2.如果尾指针在头指针前面,则当头指针减尾指针等于1时,也就是头指针紧挨着尾指针,队列已满
     * @return 是否已满
     */
    @Override
    public boolean isFull()
    {
        if (tail > head)
        {
            return tail - head == array.length - 1;
        }
        else if (tail < head)
        {
            return head - tail == 1;
        }
        else
        {
            return  false;
        }
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值