双端队列[Java]

双端队列:队首队尾都可以进行添加和删除,也是循环队列。
想象一条横着的、减元素向左加元素向右的顺序表:
队首指针front:从队首增加元素时向左移,减少时向右移;
队尾指针rear:从队尾增加元素时向右移,减少时向左移;
向后时通过 front = (front - 1 + data.length) % data.length;移动指针,
向前时通过front = (front+1) % data.length;移动指针(rear也一样)。

接口定义

先定义双端队列的接口Deque,继承队列的接口Queue

package p1.接口;
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();
}

队列的接口Queue

package p1.接口;

public interface Queue<E> extends Iterable<E> {
    public void offer(E element); //入队
    public E poll(); //出队
    public E top(); //查看队头元素
    public boolean isEmpty();
    public void clear();
    public int size(); //查看队列长度
}

双端队列类的实现

创建双端队列类继承Deque和Stack接口同时实现顺序队列和顺序栈的功能,Stack接口见栈接口定义和顺序栈的实现

package p2.线性结构;

import p1.接口.Deque;
import p1.接口.Stack;

import java.util.Iterator;
//双端队列:队首队尾都可以添加和删除
public class ArrayDeque<E> implements Deque<E>, Stack<E> {
    private E[] data; //数组容器存放元素
    private int front;//队首指针,指向当前队首元素的位置
    private int rear; //队尾指针,指向队尾元素下一次添加的位置
    private int size; //元素个数
    private static int DEFAULT_CAPACITY = 10; //默认数组容量
    
    //构造函数实现变量初始化
    public ArrayDeque(){
        data = (E[]) new Object[DEFAULT_CAPACITY+1];
        front = 0;
        rear = 0;
        size = 0;
    }
    //从队首增加元素
    @Override
    public void addFirst(E element) {
        if ((rear + 1) % data.length == front){ //如果满了则扩容
            resize(data.length * 2 -1);
        }
        front = (front - 1 + data.length) % data.length;
        data[front] = element;
        size++;
    }
    //改变数组容量
    private void resize(int newlen){
        E[] newData = (E[]) new Object[newlen];
        int index = 0;
        for (int i = front; i != rear;i = (i+1)%data.length){
            newData[index++] = data[i];
        }
        data = newData;
        front = 0;
        size = 0;
    }
    //从队尾添加元素
    @Override
    public void addLast(E element) {
        if ((rear+1)%data.length == front){
            resize(data.length * 2 - 1);
        }
        data[rear] = element;
        rear = (rear+1) % data.length;
        size++;
    }
    //从队首删除元素
    @Override
    public E removeFirst() {
        if (isEmpty()){
            throw new IllegalArgumentException("queue is null");
        }
        E ret = data[front];
        front = (front+1) % data.length;
        size --;
        if (size <= (data.length-1) / 4 && data.length-1 > DEFAULT_CAPACITY){
            resize(data.length / 2 + 1);
        }
        return ret;
    }
    //从队尾删除元素
    @Override
    public E removeLast() {
        if (isEmpty()){
            throw new IllegalArgumentException("queue is null");
        }
        rear = (rear - 1 + data.length) % data.length;
        E ret = data[rear];
        size --;
        if (size <= (data.length-1) / 4 && data.length-1 > DEFAULT_CAPACITY){
            resize(data.length / 2 + 1);
        }
        return ret;
    }
    //获取队首元素
    @Override
    public E getFirst() {
        if (isEmpty()) {
            throw new IllegalArgumentException("queue is null");
        }
        return data[front];
    }
    //获取队尾元素
    @Override
    public E getLast() {
        if (isEmpty()) {
            throw new IllegalArgumentException("queue is null");
        }
        return data[(rear - 1 + data.length) % data.length];
    }
    //入队(从队首添加)
    @Override
    public void offer(E element) {
        addFirst(element);
    }
    //出队(从队首减少)
    @Override
    public E poll() {
        return removeFirst();
    }
    //查看队首元素
    @Override
    public E top() {
        return getFirst();
    }
    //判空
    @Override
    public boolean isEmpty() {
        return size == 0 && front == rear;
    }
    //入栈(从队尾添加元素)
    @Override
    public void push(E element) {
        addLast(element);
    }
    //弹栈(从队首添加元素)
    @Override
    public E pop() {
        return removeLast();
    }
    //查看栈顶(队尾元素)
    @Override
    public E peek() {
        return getLast();
    }
    //清空
    @Override
    public void clear() {
        E[] data = (E[]) new Object[DEFAULT_CAPACITY];
        front = 0;
        rear = 0;
        size = 0;
    }
    //查看元素个数
    @Override
    public int size() {
        return size;
    }
    //输出形式
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('[');
        if (isEmpty()) {
            sb.append(']');
            return sb.toString();
        }
        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(',');
                sb.append(' ');
            }
        }
        return sb.toString();
    }
    //判断两个队是否相等(对内元素)
    @Override
    public boolean equals(Object o){
        if(o == null){
            return false;
        }
        if (this == o){
            return true;
        }
        if (o instanceof ArrayDeque){
            ArrayDeque<E> other = (ArrayDeque<E>) o;
            if (size != other.size()){
                return false;
            }
            int i = front;
            int j = other.front;
            while (i != rear){
                if (!data[i].equals(other.data[j])){
                    return false;
                }
                i = (i + 1) % data.length;
                j = (j + 1) % other.data.length;
            }
        }
        return true;
    }
    //迭代器
    @Override
    public Iterator<E> iterator() {
        return new ArrayDequeIterator();
    }

    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 p2.线性结构;

import java.io.File;

public class DirectoryTraversal {
    public static void main(String[] args) {
        File dir = new File("C:\\Users\\86138\\Desktop\\DS");//添加要遍历的文件夹的绝对地址
        ArrayLoopQueue<File> queue = new ArrayLoopQueue<>();
        queue.offer(dir);
        while (!queue.isEmpty()){
            File file = queue.poll();
            System.out.println("【" + file.getName() + "】");
            File[] files = file.listFiles(); //将出队的目录展开
            for (File f:files){
                if (f.isFile()){
                    System.out.println(f.getName());
                }else {
                    queue.offer(f);
                }
            }
        }
    }
}

/* * 基于双向链表实现双端队列结构 */ 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、付费专栏及课程。

余额充值