双端队列:队首队尾都可以进行添加和删除,也是循环队列。
想象一条横着的、减元素向左加元素向右的顺序表:
队首指针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);
}
}
}
}
}