双端栈、队列

4. 双端栈(ArrayDoubleEndStack)
(1)双端栈的定义

双端栈 是指将一个线性表的两端当做栈底分别进行入栈和出栈操作
主要利用了栈 栈底位置不变,而栈顶位置动态变化 的特性。

image-20220114171354734

双端栈的特点:

  • 双端栈是线性表的一种,更是栈的一个特殊分类
  • 所以我们可以用动态数组和栈的思想来实现双端栈
  • 毕竟由于其操作过于特殊,并不能借助ArrayList或ArrayStack实现
  • 所以这里从头开始实现双端栈
(2)双端栈的扩容、缩容问题

image-20220114171846722

(3)代码实现
package test;

import java.util.Iterator;

public class ArrayDoubleEndStack<E> implements Iterable<E> {
    private int ltop;//左端栈顶
    private int rtop;//右端栈顶

    private E[] data;
    private static int DAFUALT_CAPACITY = 10;

    public ArrayDoubleEndStack(){
        data = (E[]) new Object[DAFUALT_CAPACITY];
        ltop = -1;
        rtop = data.length;
    }
    public ArrayDoubleEndStack(int capacity){
        DAFUALT_CAPACITY = capacity;
        data = (E[]) new Object[DAFUALT_CAPACITY];
        ltop = -1;
        rtop = data.length;
    }
    public void pushLeft(E element){
        if (ltop + 1 == rtop) {
            resize(data.length * 2);
        }
        data[++ ltop] = element;
    }

    public void pushRight(E element){
        if (ltop + 1 == rtop) {
            resize(data.length * 2);
        }
        data[-- rtop] = element;
    }
    private void resize(int newLen) {
        E[] newData = (E[]) new Object[newLen];
        for (int i = 0; i < ltop; i++) {
            newData[i] = data[i];
        }
        //复制右端栈的元素
        int index = rtop;
        for (int i = newLen - sizeRight(); i < newLen; i++) {
            newData[i] = data[index ++];
        }
        rtop = newLen - sizeRight() - 1;
        data = newData;
    }
    public E popLeft(){
        if (isLeftEmpty()) {
            throw new IllegalArgumentException("Left Stack Is Empty");
        }
        E ret = data[ltop --];
        if (sizeLeft()+sizeRight() <= data.length / 4 && data.length > DAFUALT_CAPACITY){
            resize(data.length/2);
        }
        return ret;
    }
    public E popRight(){
        if (isRightEmpty()) {
            throw new IllegalArgumentException("Left Stack Is Empty");
        }
        return data[rtop ++];
    }
    public E peekLeft(){
        if (isLeftEmpty()) {
            throw new IllegalArgumentException("Left Stack Is Empty");
        }
        return data[ltop];
    }
    public E peekRight(){
        if (isRightEmpty()) {
            throw new IllegalArgumentException("Left Stack Is Empty");
        }
        return data[rtop];
    }
    public boolean isLeftEmpty(){
        return ltop == -1;
    }
    public boolean isRightEmpty(){
        return rtop == data.length;
    }
    public int sizeRight(){
        return ltop + 1;
    }
    public int sizeLeft(){
        return data.length-rtop;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('[');
        if (isLeftEmpty() && isRightEmpty()){
            sb.append(']');
        }

        for (int i = 0; i <= ltop; i++) {
            sb.append(data[i]);
            if (i == ltop && isRightEmpty()){
                sb.append(']');
            }else{
                sb.append(',');
            }
        }
        for (int i = rtop; i < data.length; i++) {
            sb.append(data[i]);
            if (i == data.length-1) {
                sb.append(']');
            }else{
                sb.append(',');
            }
        }
        return sb.toString();
    }

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

第三节 队列

1.队列的定义

队列 是只允许在一端进行插入操作,而在另一端进行删除操作的线性表

我们把允许删除的一端称为队首(front),插入的一端称为队尾(rear)

队列有以下基本概念:

  • 不含任何数据元素的队列称为空队列
  • 队列是一种先进先出(First In Last Out)的线性表,简称FIFO
  • 队列本身是一个线性表,其数据元素具有线性关系,只不过它是一种特殊的线性表而
  • 队列的插入操作,叫作入队
  • 队列的删除操作,叫作出队
2. 队列接口的定义

同样队列可以顺序存储实现也可以链表存储实现,所以将共性抽取定义出Queue接口

public interface Queue<E> extends Iterable<E> {    
    public int size();    //队中元素数量
    public boolean isEmpty();   //队空判断
    public void offer(E element);//入队
    public E poll();//出队
    public E peek();//获取队首元素
    public void clear();//清空队列
}
3.ArrayQueue类

该类为队列的顺序存储具体实现,因为队列本身就是一种特殊的线性表,所以我们可以借用之前完成的ArrayList来实现我们的ArrayQueue

package p2.array.lists;

import p1.interfaces.Queue;

import java.util.Iterator;
import java.util.Objects;

public class ArrayQueue<E> implements Queue<E> {
    private ArrayList<E> list;
    public ArrayQueue(){
        list = new ArrayList<>();
    }
    @Override
    public int size() {
        return list.size();
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public void offer(E element) {
        list.add(list.size(),element);
    }

    @Override
    public E poll() {
        return list.remove(0);
    }

    @Override
    public E element() {
        return list.get(0);
    }

    @Override
    public void clear() {
        list.clear();
    }

    @Override
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if(this == o){
            return true;
        }
        if (o instanceof ArrayQueue){
            ArrayQueue other = (ArrayQueue) o;
            return list.equals(other.list);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return Objects.hash(list);
    }

    @Override
    public String toString() {
        return list.toString();
    }

    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }
}
4.队列实现文件夹遍历

image-20220114173627094

树形图层序遍历的方法,如果是个目录,则入队,如果是文件,则直接打印文件名

代码如下:

package test;

import p2.array.lists.ArrayQueue;

import java.io.File;

public class DirTraversal {
    public static void main(String[] args) {
        File dir = new File("E:\\WorkSpace\\Java");
        ArrayQueue<File> dirs = new ArrayQueue<>();
        dirs.offer(dir);
        /*
        *
        * 只要队列不为空,则出队一个对象,将该目录打开遍历,遇到目录进队。遇到文件打印
        * 直到队列为空
        *
        * */
        while (!dirs.isEmpty()){
            File file = dirs.poll();
            System.out.println("【"+file.getName()+"】");
            File[] files = file.listFiles();
            for (File f : files){
                if(f.isFile()){
                    System.out.println(f.getName());
                }else{
                    dirs.offer(f);
                }
            }
        }
    }
}
5.用栈实现队列
package test;

import p1.interfaces.Queue;
import p2.array.lists.ArrayStack;

import java.util.Iterator;

public class StackImQueue {
    public static void main(String[] args) {
        QueueImByStack<Integer> nums = new QueueImByStack<>();
        for (int i = 0; i < 10; i++) {
            nums.offer(i);
        }
        System.out.println(nums);
        System.out.println(nums.poll());
        System.out.println(nums);
    }
}
class QueueImByStack<E> implements Queue<E> {
    private ArrayStack<E>  stackA;
    private ArrayStack<E>  stackB;

    public QueueImByStack(){
        stackA = new ArrayStack<>();
        stackB = new ArrayStack<>();
    }

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

    @Override
    public boolean isEmpty() {
        return stackA.isEmpty();
    }

    @Override
    public void offer(E element) {
        stackA.push(element);
    }

    @Override
    public E poll() {
        while (stackA.size() != 1){
            stackB.push(stackA.pop());
        }
        E ret = stackA.pop();
        while(!stackB.isEmpty()){
            stackA.push(stackB.pop());
        }
        return ret;
    }

    @Override
    public E element() {
        while (stackA.size() != 1){
            stackB.push(stackA.pop());
        }
        E ret = stackA.peek();
        while(!stackB.isEmpty()){
            stackA.push(stackB.pop());
        }
        return ret;
    }

    @Override
    public void clear() {
        stackA.clear();
    }

    @Override
    public String toString() {
        return stackA.toString();
    }

    @Override
    public Iterator iterator() {
        return stackA.iterator();
    }
}
6.循环队列(ArrayLoopQueue)

该循环队列的实现思想也是动态数组,但是由于操作元素的特殊性,并不能直接由ArrayList或ArrayQueue实现,所以从头开始定义ArrayLoopQueue

image-20220114174642102

package p2.array.lists;

import p1.interfaces.Queue;

import java.util.Iterator;

public class ArrayLoopQueue<E> implements Queue<E>{
    private E[] data;
    private int front;
    private int rear;
    private int size;
    private static int DAFAULT_CAPACITY = 10;

    public ArrayLoopQueue(){
        data =(E[])new Object[DAFAULT_CAPACITY + 1];
        front = 0;
        rear = 0;
        size = 0;
    }
    @Override
    public int size() {
        return size;

    }

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

    @Override
    public void offer(E element) {
        if((rear + 1 ) % data.length == front){
            resize(data.length * 2 - 1);
        }
        data[rear] = element;
        rear = (rear + 1 ) % data.length;
        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;
        rear = index;
    }

    @Override
    public E poll() {
        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 > DAFAULT_CAPACITY){
            resize((data.length+1)/2);
        }
        return ret;
    }

    @Override
    public E element() {
        if(isEmpty()){
            throw new IllegalArgumentException("queue is null");
        }
        return data[front];
    }

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

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('[');
        if (isEmpty()){
            sb.append(']');
        }
        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 ArrayLoopQueue){
            ArrayLoopQueue<E> other = (ArrayLoopQueue<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;
        }
        return false;
    }



    @Override
    public Iterator<E> iterator() {
        return new ArrayLoopQueueIterator();
    }
    class ArrayLoopQueueIterator implements Iterator<E>{
        private int cur = front;

        @Override
        public boolean hasNext() {

            return cur != front;
        }

        @Override
        public E next() {
            E ret = data[cur];
            cur = (cur + 1) % data.length;
            return ret;
        }
    }
}
7. 双端队列

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

image-20220114174753192

(1)双端队列的接口实现
package p1.interfaces;

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();
}

(2)双端队列的代码实现
package p2.array.lists;

import p1.interfaces.Deque;
import p1.interfaces.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 DAFAULT_CAPACITY = 10;
    public ArrayDeque(){
        data = (E[]) new Object[DAFAULT_CAPACITY + 1];
        front = 0;
        size = 0;
        rear = 0;
    }
    @Override
    public void addFirst(E element) {
        if ((rear + 1) % data.length-1 == front){
            resize(data.length*2-1);
        }
        front = (front - 1 + data.length) %data.length;
        data[front] = element;
        size ++;
    }

    @Override
    public void addLast(E element) {
        if (size == data.length-1){
            resize(data.length*2-1);
        }
        data[rear] = element;
        rear = (rear + 1) % data.length;
        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;
        rear = index;
    }

    @Override
    public E removeFirst() {
        return null;
    }

    @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 > DAFAULT_CAPACITY){
            resize((data.length-1) / 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 int size() {
        return size;
    }

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

    @Override
    public void push(E element) {

    }

    @Override
    public E pop() {
        return null;
    }

    @Override
    public E peek() {
        return getLast();
    }

    @Override
    public void offer(E element) {
        addLast(element);
    }

    @Override
    public E poll() {
        return removeFirst();

    }

    @Override
    public E element() {
        return getFirst();
    }

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

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('[');
        if (isEmpty()){
            sb.append(']');
        }
        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;
        }
        return false;
    }



    @Override
    public Iterator<E> iterator() {
        return new ArrayDeque<E>.ArrayDequeIterator();
    }
    class ArrayDequeIterator implements Iterator<E>{
        private int cur = front;
        @Override
        public boolean hasNext() {
            return cur != front;
        }

        @Override
        public E next() {
            E ret = data[cur];
            cur = (cur + 1) % data.length;
            return ret;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值