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

39 篇文章 2 订阅

写在前面的话:

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

完 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
/* * 基于双向链表实现双端队列结构 */ 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.getNext(); } System.out.println(); } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fy哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值