双端队列数组版【Java算法(五)】

写在前面的话:

1.熟悉栈、队列相关知识

2.熟悉数组的中间插入

3.熟悉数组如何扩容


目录

1.双端队列

 2.测试双端队列


 

项目结构:(双端队列同样属于栈&队列范畴)

 

 

1.双端队列

Deque.java
/*
    双端队列:[拓展知识]

    简单的介绍:
        1.为了充分利用数组空间,特此采用循环队列
        2.本程序考察了参数的应用、数组的中间插入和超范围插入(扩容)
        3.存储方式可以用数组外,还可以采用链表(本程序当中未涉及)

    技巧:
        1.熟悉栈与队列,之后无障碍阅读
        2.熟悉数组的中间插入
        3.熟悉数组如何进行扩容
 */

public class Deque {

    private int[] array;
    private int font;//双端队列也是队列!同样有队头
    private int rear;
    int size;//元素个数

    public Deque(){
        array = new int[10];
    }

    //指定长度的队列
    public Deque(int capacity){
        array = new int[capacity];
    }

    /**
     * 入队
     * @param element 插入的元素
     * @param front_or_behind 从后面插入元素(参数填入:behind)还是前面插入元素(参数填入:front)
     */
    public void enDeque(int element,String front_or_behind){

        //不管是在前面插入或者后面插入,当队列为空时,插入元素只有1种可能
        if(size == 0){
            array[0] = element;
            rear += (rear + 1)%array.length;
            size++;
            return;//插入完毕,直接返回
        }

        //判断插入顺序
        if(front_or_behind == "front"){
            //判断队列是否已满
            if(size >= array.length - 1){//元素个数大于或等于数组长度(要留一个,故减一)
                //进行扩容
                expandCapacity();
            }
            //队列未满可进行插入
            insert(font,element);//在队头插入数据
        }else if(front_or_behind == "behind"){
            //判断队列是否已满
            if(size >= array.length - 1){//元素个数大于或等于数组长度(要留一个空,故减一)
                //进行扩容
                expandCapacity();
            }
            //队列未满可进行插入
            array[rear] = element;
            rear = (rear + 1)%array.length;
            size++;//元素个数加1
        }else{
            //输入有误
            throw new IllegalArgumentException("输入参数有误!非front或behind!");
        }
    }

    /**
     * 出队
     * @param front_or_behind 从后面删除元素(参数填入:behind)还是前面删除元素(参数填入:front
     */
    public void outDeque(String front_or_behind) throws Exception{

        //判断队列是否为空
        if(size == 0){
            throw new Exception("队列为空,无法获取数据");
        }

        if(front_or_behind == "front"){
            font = (font + 1)%array.length;
            size--;//元素个数减一
        }else if(front_or_behind == "behind"){
            rear--;
            if(rear <= -1){
                rear = array.length - 1;
            }
            size--;//元素个数减一
        }else{
            throw new IllegalArgumentException("输入参数有误!非front或behind!");
        }
    }

    public void expandCapacity(){

        int[] newArray = new int[array.length * 2];

        if(newArray.length > 100){
            throw new IllegalArgumentException("不准栈的深度超过100");
        }

        //将原数组复制到新数组里
        for(int i = font,n = 0;n < size;i = (i + 1)%array.length){
            newArray[n++] = array[i];
        }

        //扩大后,队头队尾发生变化
        font = 0;
        rear = size;

        array = newArray;
    }

    /**
     * 数组的中间插入、超范围插入(扩容)
     * @param index    插入的位置
     * @param element  插入的元素
     */
    public void insert(int index , int element){

        //在这里不需要判断是否需要扩容,在调用该方法前已经判断了

        //判断index是否超出数组范围
        if(index < 0 || index > array.length){//还不完善,有能力可以进一步修改
            throw new IllegalArgumentException("参数index不符合范围!参数index的值:" + index);
        }

        //在数组下标index以及之后的元素依次往后移动(记住:这里是循环队列!如:array[array.length] == array[0])
        //
        //    在这里分两种情况:
        //        1.rear后面没有接元素:这种比较简单,元素依次往后移一位【常规写法】
        //        2.rear后面有元素(队尾在中间):这种比较麻烦,关键在于后面有个元素是队头
        //
        if(rear >= font){
            //这种情况说明:常规情况,[1,font,...,2,3,4,rear]
            for(int i = rear - 1;i >= index;i--){
                array[i + 1] = array[i];//往后移
            }
        }else{
            //这种情况说明:[1,2,rear,...,3,4,font,...]
            for(int i = rear - 1;i != index;i--){
                if(i <= -1){
                    i = array.length - 1;
                    array[0] = array[i];
                    continue;
                }
                array[i + 1] = array[i];
            }
            array[(index + 1)%array.length] = array[index];//将队头向后移
        }

        //将元素插入数组下标index处  ==> 数组更新操作
        array[index] = element;

        //插入后,元素个数增加,队尾加1
        size++;
        rear = (rear + 1)%array.length;
    }

    @Override
    public String toString() {
        String str = "[";
        //只遍历数组当中的元素个数
        //   分两种情况:
        //      1. rear >= font [1,font,...,2,3,4,rear]
        //      2. rear < font  [1,2,rear,...,3,4,font,...]
        if(rear >= font){
            //常规解法,依次遍历即可
            for(int i = font;i < rear;i = (i + 1)%array.length){
                str += array[i];
                //当不是最后1个元素,需要加逗号
                if(i != rear - 1){
                    str += ",";
                }
            }
        }else{
            //rear < font情况
            for(int i = font;i < size;i = (i + 1)%array.length){
                str += array[i];
                //当不是最后1个元素,需要加逗号
                if(i != rear - 1){
                    str += ",";
                }
            }
        }

        //最后加一个"]"结尾
        str += "]";
        return str;
    }
}

 2.测试双端队列

TestArray.java
public class TestArray {

    public static void main(String[] args) {

        Deque deque = new Deque(3);

        System.out.println("入队:");

        deque.enDeque(1,"behind");
        deque.enDeque(2,"behind");
        deque.enDeque(3,"front");
        deque.enDeque(4,"front");
        deque.enDeque(5,"behind");
        deque.enDeque(6,"behind");
        deque.enDeque(7,"front");

        System.out.println(deque);

        System.out.println("出队:");

        try {
            deque.outDeque("front");
            deque.outDeque("behind");
            deque.outDeque("front");
            deque.outDeque("front");
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(deque);

        System.out.println("入队:");
        deque.enDeque(-1,"front");
        deque.enDeque(6,"behind");
        deque.enDeque(-4,"front");
        deque.enDeque(-5,"behind");

        System.out.println(deque);

        System.out.println("出队:");

        try {
            deque.outDeque("front");
            deque.outDeque("behind");
            deque.outDeque("front");
            deque.outDeque("front");
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(deque);
    }
}

完 

 

posted @ 2022-04-01 10:28  辰梦starDream  阅读(1)  评论(0编辑  收藏  举报  来源