双端队列[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);
                }
            }
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值