Java数据结构与算法笔记_day03(双端队列的实现)

双端队列的实现

双端队列的定义

双端队列(double ended queue ,deque)是限定插入和删除操作在表的两端进行的线性表,是一种具有队列和栈的性质的数据结构

图解双端队列的操作

在这里插入图片描述

双端队列Dequeue接口的定义

public interface Deque<E> extends Queue<E> {
    public void addFirst(E element);
    public void addLast(E element);
    public E removeFirst();
    public E removeLast();
    public E getFirst();
    public E getLast();
    public int size();
    public boolean isEmpty();
    public void clear();
}

双端队列ArrayDequeue类的代码实现

  • 双端队列 除了有自身的特点之外 也可以当做队列 和 栈去使用
  • 没有提供可以在任意角标处操作元素的功能(List)
  • 在头的增删 在尾的增删 时间复杂度都是O(1) resize()达到O(n)
public class ArrayDeque<E> implements Deque<E> , Stack<E> {

    private E[] data;
    private int front;  //队首指针 front == rear 双端队列为空
    private int rear;   //对尾指针 (rear + 1) % len == front 双端队列满了
    private int size;   //有效元素的个数
    private static int DEFAULT_SIZE = 10;

    public ArrayDeque(){
        this(DEFAULT_SIZE);
    }

    public ArrayDeque(int capacity){
        data =(E[]) new Object[capacity + 1];
        front = 0;
        rear = 0;
        size = 0;
    }

    //在Deque的队首添加一个元素
    @Override
    public void addFirst(E element) {
    //先判断Deque是否是满的
        if (isExpansion()){
            resize(data.length * 2 - 1);
        }
        front = (front - 1 + data.length) % data.length;
        data[front] = element;
        size++;
    }

    private void resize(int newLength) {
        E[] newData =(E[]) new Object[newLength];
        int index = 0;
        for (int i = front; i != rear; i = (i + 1) % data.length) {
            newData[index++] = data[i];
        }
        front = 0;
        rear = index;
        data = newData;
    }

    //判断Deque是否需要扩容-判断是否是满的
    private boolean isExpansion() {
        return (rear + 1) % data.length == front;
    }

    //在Deque的队尾添加一个元素
    @Override
    public void addLast(E element) {
        //先判断Deque是否是满的
        if (isExpansion()){
            resize(data.length * 2 - 1);
        }
        data[rear] = element;
        rear = (rear + 1) % data.length;
        size++;
    }

    //在Deque队首删除一个元素
    @Override
    public E removeFirst() {
        if (isEmpty()) {
            throw new NullPointerException("Deque is empty");
        }
        E ret = data[front];
        front = (front + 1) % data.length;
        size--;
        //再判断是否需要缩容
        if (isShrink()){
            resize(data.length / 2 + 1);
        }
        return ret;
    }

    //判断Deque是否需要缩容-判断是否是空的
    private boolean isShrink() {
        return size ==(data.length - 1) / 4 && data.length - 1 > DEFAULT_SIZE;
    }

    //在Deque队尾删除一个元素
    @Override
    public E removeLast() {
        if (isEmpty()){
            throw new NullPointerException("Deque is empty");
        }
        rear = (rear - 1 + data.length) % data.length;
        E ret = data[rear];
        size--;
        if (isShrink()){
            resize(data.length / 2 + 1);
        }
        return ret;
    }

    @Override
    public E getFirst() {
        return data[front];
    }

    @Override
    public E getLast() {
        return data[(rear - 1 + data.length) % data.length];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0 && front == rear;
    }

    //栈 入栈 -> addLast() front栈底 rear栈顶
    @Override
    public void push(E element) {
        addLast(element);
    }

    //栈 出栈 -> removeLast() front栈底 rear栈顶
    @Override
    public E pop() {
        return removeLast();
    }

    //获取栈顶元素 getLast() front栈底 rear栈顶
    @Override
    public E peek() {
        return getLast();
    }

    //队列 入队 -> addLast() front队首 rear队尾
    @Override
    public void offer(E element) {
        addLast(element);
    }

    //队列 出队 -> removeFirst() front队首 rear队尾
    @Override
    public E poll() {
        return removeFirst();
    }

    //队列 获取队首元素 -> getFirst() front队首 rear队尾
    @Override
    public E element() {
        return getFirst();
    }

    @Override
    public void clear() {
        data = (E[]) new Object[DEFAULT_SIZE + 1];
        front = 0;
        rear = 0;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(String.format("ArrayDeque:%d/%d[",size,data.length - 1));
        if (isEmpty()){
            sb.append(']');
        } else{
            for (int i = front; i != rear ; i = (i + 1) % data.length) {
                sb.append(data[i]);
                if ((i + 1) % data.length == rear){
                    sb.append(']');
                }else {
                    sb.append(',');
                }
            }
        }
        return sb.toString();
    }

    @Override
    public Iterator<E> iterator() {
        return new ArrayDequeIterator();
    }

    //默认的迭代器方向是从front-rear
    class ArrayDequeIterator implements Iterator<E> {

        private int cur = front;

        @Override
        public boolean hasNext() {
            return cur != rear;
        }

        @Override
        public E next() {
            E ret = data[cur];
            cur = (cur + 1) % data.length;
            return ret;
        }
    }
}
/* * 基于双向链表实现双端队列结构 */ package dsa; public class Deque_DLNode implements Deque { protected DLNode header;//指向头节点(哨兵) protected DLNode trailer;//指向尾节点(哨兵) protected int size;//队列中元素的数目 //构造函数 public Deque_DLNode() { header = new DLNode(); trailer = new DLNode(); header.setNext(trailer); trailer.setPrev(header); size = 0; } //返回队列中元素数目 public int getSize() { return size; } //判断队列是否为空 public boolean isEmpty() { return (0 == size) ? true : false; } //取首元素(但不删除) public Object first() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return header.getNext().getElem(); } //取末元素(但不删除) public Object last() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return trailer.getPrev().getElem(); } //在队列前端插入新节点 public void insertFirst(Object obj) { DLNode second = header.getNext(); DLNode first = new DLNode(obj, header, second); second.setPrev(first); header.setNext(first); size++; } //在队列后端插入新节点 public void insertLast(Object obj) { DLNode second = trailer.getPrev(); DLNode first = new DLNode(obj, second, trailer); second.setNext(first); trailer.setPrev(first); size++; } //删除首节点 public Object removeFirst() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = header.getNext(); DLNode second = first.getNext(); Object obj = first.getElem(); header.setNext(second); second.setPrev(header); size--; return(obj); } //删除末节点 public Object removeLast() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = trailer.getPrev(); DLNode second = first.getPrev(); Object obj = first.getElem(); trailer.setPrev(second); second.setNext(trailer); size--; return(obj); } //遍历 public void Traversal() { DLNode p = header.getNext(); while (p != trailer) { System.out.print(p.getElem()+" "); p = p.getNex
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值