队列基本构造和应用

队列的基本概念

队列是一种线性结构,一种抽象的结构,可以用数组实现或者链表实现。
用数组实现的队列叫顺序队列,用链表实现的队列叫链式队列。

队列的特点就是先进先出,先进队列,后面的元素想出队列必须要排队。 引出两个基本的操作,入队enquence()和出队dequence()。

队列是一种很基础的结构,应用非常广泛,比如循环队列、阻塞队列、并发队列,

基于java构建顺序队列基本结构

入队:新元素放在队列的时候,只允许在队尾放进元素,新元素成为队尾。
出队:只允许把队头元素移出元素,出队元素的后一个元素成为新的队头。
队头:front
队尾:rear

下面是构建队列的代码:

package java_test;

public class MyQuence {
    private String[] arr; //数组
    private int n = 0; //数组大小
    private int head = 0;//队头
    private int tail = 0;//队尾

    private MyQuence(int capacity){
        arr = new String[capacity];
        n = capacity;
    }
    public Boolean equence(String iterm ){
        if (tail ==n){
            return  false;
        }
        arr[tail] = iterm;
        ++tail;
        return true;
        }
    public String dequence(){
        if (head ==tail ) return null;
        String ret = arr[head];
        ++head;
        return ret;
    }
    public void output(){
        for (int i=0; i<n;++i){
            System.out.print("对垒"+arr[i]);
        }
        System.out.println("  ");
    }

    public static void main(String[] args) {
        MyQuence myQuence = new MyQuence(3);
        myQuence.equence("chen");
        myQuence.equence("asddasf");      
        myQuence.equence("kasda");
        myQuence.output();
        myQuence.dequence();
        myQuence.output();

    }

}

看上去好像很复杂,但其实只要指定两个指针即可。一个是head指针,指向队头,一个是tail指针,指向队尾。一开始tail和head都指向数据的坐标0位置
当元素进队的时候,tail指针往队尾移动,这样tail就会越来越大,head就自动成为了队头,这时候出队就从队头开始出,即head=0的时候,head也往后移。等到队头=队尾的时候,表示队列为空。
在这里插入图片描述

这样随着进队、出队的操作执行,head、tail都往后移动,当tail移动到最后的时候,即使数组有剩余空间也无法添加数据了。
如果解决这种问题呢,数据迁移,当没有空间的时候触发一次数据迁移。修改一下入队函数如下:

    public Boolean equence(String iterm){
        if (tail ==n){
            if (head==0) return false;
            for (int i= head; i<tail; ++i){
                arr[i-head] = arr[i];
            }
            tail = tail -head;
            head = 0;
        }
        arr[tail] = iterm;
        ++tail ;
        return true;
    }

在这里插入图片描述

循环队列

数据迁移操作后,入队操作性能就会受到影响,那如何避免数据迁移呢,就引出了循环队列。

在这里插入图片描述
队列大小为8,当head=4的时候,tail=7,当有一个新元素进入的时候,我们不把tail更新为8,而是往后移动一位,到下标为0的位置。当再有一名元素进队,把新元素放到下标为0。就变成了这样。
在这里插入图片描述

这样就避免了数据迁移。针对于循环队列,关键要判断队空和队满。
队空的条件还是tail=head。
队满的条件则是(tail+1)%n=head
tail =3,head = 4,n=8,(3+1)%8=4

此外,tail指向的位置实际上是没有存储数据的,所以循环队列会浪费一个数组块的存储空间

循环队列代码如下:

package java_test;

public class CircularQuene {
    private String[] arr;
    private int n = 0;
    private  int head = 0;
    private  int tail = 0;
    public CircularQuene(int capacity){
        arr = new String[capacity];
        n = capacity;
    }

    public boolean enquence(String iterm){
        if ((tail+1)%n==head) return false;
        arr[tail]= iterm;
        tail = (tail+1)%n;
        return  true;
    }
    public String dequence(){
        if (head ==tail) return null;
        String ret = arr[head];
        head =(head+1)%n;
        return  ret;
    }

    public static void main(String[] args) {
        CircularQuene circularQuene = new CircularQuene(5);
        circularQuene.enquence("as");
        circularQuene.enquence("as");
        circularQuene.enquence("as");
        circularQuene.enquence("as");
        circularQuene.enquence("as");
        circularQuene.enquence("as");
        circularQuene.enquence("as");
        circularQuene.enquence("as");
        circularQuene.enquence("as");
        circularQuene.enquence("as");
        circularQuene.enquence("as");
    }
}

阻塞队列

阻塞队列就是在队列的基础上加上了阻塞操作,当队列为空的时候,从队头取数就会被阻塞,因为此时没数可取,直至有数据了才返回。
当队列满了后,插入数据则会被阻塞,直至有了空闲数据再插入数据,然后返回。
在这里插入图片描述
阻塞队列的定义也是一个”生产者-消费者模型“,可以有效协调生产和消费的速度。当生产者生产数据块,消费者来不及消费的时候,存储数据的队列就很快被填满,生产者就阻塞。直至有了消费者消费了数据,生产者才会被唤醒进行生产数据。

并发队列

多线程的情况下操作队列,就会存在线程安全问题。
线程安全的队列称为并发队列。最简单的实现方式就是再enquence()方法、dequence()方法进行加锁,但是锁 粒度并发度会比较底,同一时刻只允许一个存一个取。实际上如果是基于数组的循环队列,可以利用CAP原子操作实现高效的并发队列。

线程池没有空闲线程,有新请求时,线程池如何处理。

1.非阻塞的处理方式,直接拒绝任务请求。
2.进行阻塞的处理方式,等到有空闲线程再取出排队中的请求。那么如何存储排队的请求呢

如果希望先来先到、比较公平的方式的话,可以用队列存储。但是队列有基于数据的顺序队列和基于链表的链表队列。

基于链表的队列可以支持无限排队的无界队列,但是过多的请求导致过多的排队,请求处理的响应时间过长。所以针对响应时间比较敏感的系统,是不合适使用基于链表无线排队的线程池的。

基于数据的队列,队列大小有限,排队的请求超过队列大小的时候,接下来的请求会被拒绝。这种方式对响应时间敏感的系统比较合理。但是如何设置一个合适 的队列大小也是很讲讲究的。

对于大部分资源有限的场景,当没有空闲资源的时候,基本可以通过队列来实现请求排队。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值