08队列

1.概念

先进者先出,是一种操作受限的线性结构,只有两种操作:入队enquque()出队dequeue().

2.分类

基于数组实现的叫顺序队列,基于链表实现的叫链式队列.

2.1顺序队列

2.1.1 不可变大小的队列

package com.desmond.codebase.algorithm.queue;

/**
 * 固定大小的顺序队列
 * @author presleyli
 * @date 2019/1/7 12:51 PM
 */
public class FixedArrayQueue {
    private String[] arr;

    private int n;
    private int head = 0;
    private int tail = 0;

    public FixedArrayQueue(int n) {
        this.n = n;
        this.arr = new String[n];
    }

    /**
     * O(1)
     * @param ele
     * @return
     */
    public boolean enQueue(String ele) {
        if(tail == n) { // 1
            return false;
        }

        arr[tail++] = ele; // 1

        return true;
    }

    /**
     * O(1)
     * @return
     */
    public String deQueue() {
        if(head == tail) { // 1
            return "";
        }

        String ele = arr[head++]; // 1

        return ele;
    }

    public static void main(String[] args) {
        FixedArrayQueue arrayQueue = new FixedArrayQueue(3);

        System.out.println(arrayQueue.enQueue("1"));
        System.out.println(arrayQueue.enQueue("2"));
        System.out.println(arrayQueue.enQueue("3"));
        System.out.println(arrayQueue.enQueue("4"));

        System.out.println(arrayQueue.enQueue("5"));

        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
    }
}

2.1.2 可变大小的顺序队列

package com.desmond.codebase.algorithm.queue;

/**
 * 可扩容的顺序队列-无限扩容.
 * @author presleyli
 * @date 2019/1/7 12:51 PM
 */
public class ChangeableArrayQueue {
    private String[] arr;

    private int n;
    private int head = 0;
    private int tail = 0;

    public ChangeableArrayQueue(int n) {
        this.n = n;
        this.arr = new String[n];
    }

    /**
     * 最好:O(1)
     * 最坏: O(n)
     * 平均(均摊): O(1)
     * @param ele
     * @return
     */
    public boolean enQueue(String ele) {
        if(tail == n) { // 1
            ensureCapable();
        }

        arr[tail++] = ele; // 1

        return true;
    }

    /**
     * 扩容.
     * O(n)
     */
    public void ensureCapable() {
        int newSize = n * 2;

        String[] newArr = new String[newSize];
        System.arraycopy(arr, 0, newArr, 0, n);

        n = newSize;
        arr = newArr;
    }

    /**
     * O(1)
     * @return
     */
    public String deQueue() {
        if(head == tail) { // 1
            return "";
        }

        String ele = arr[head++]; // 1

        return ele;
    }

    public static void main(String[] args) {
        ChangeableArrayQueue arrayQueue = new ChangeableArrayQueue(2);

        System.out.println(arrayQueue.enQueue("1"));
        System.out.println(arrayQueue.enQueue("2"));
        System.out.println(arrayQueue.enQueue("3"));
        System.out.println(arrayQueue.enQueue("4"));
        System.out.println(arrayQueue.enQueue("5"));
        System.out.println(arrayQueue.enQueue("6"));

        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
    }
}

2.1.3 利用固定长度,可变的顺序队列

package com.desmond.codebase.algorithm.queue;

/**
 * 可变顺序队列-利用固定arr本身剩余空间.
 * @author presleyli
 * @date 2019/1/7 12:51 PM
 */
public class ChangeableArrayQueueV2 {
    private String[] arr;

    private int n;
    private int head = 0;
    private int tail = 0;

    public ChangeableArrayQueueV2(int n) {
        this.n = n;
        this.arr = new String[n];
    }

    /**
     * 最好:O(1)
     * 最坏: O(n)
     * 平均(均摊): O(1)
     * @param ele
     * @return
     */
    public boolean enQueue(String ele) {
        if(tail == n) { // 1
            // 如果已经是第一个了,表明无元素出队,
            // 队列满了
            if(head == 0) {
                return false;
            }

            // 不扩充arr容量,搬迁.
            /*
                最好: head = tail - 1, 只搬移一个元素:O(1)
                最坏: head = 1, 搬移 n-1个元素:O(n)
                平均: 1*(1/(n-1)) + 2*(1/(n-1))
                 + 3*(1/(n-1)) + (n-1)*(1/(n-1)) = n²/(2n-2) -> O(n)
             */
            for(int i= head; i < tail; i++) {
                arr[i-head] = arr[i];
            }

            tail = tail - head;
            head = 0;
        }

        arr[tail++] = ele; // 1

        return true;
    }

    /**
     * O(1)
     * @return
     */
    public String deQueue() {
        if(head == tail) { // 1
            return "";
        }

        String ele = arr[head++]; // 1

        return ele;
    }

    public static void main(String[] args) {
        ChangeableArrayQueueV2 arrayQueue = new ChangeableArrayQueueV2(2);

        System.out.println(arrayQueue.enQueue("1"));
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.enQueue("2"));
        System.out.println(arrayQueue.enQueue("3"));
        System.out.println(arrayQueue.enQueue("4"));
        System.out.println(arrayQueue.enQueue("5"));
        System.out.println(arrayQueue.enQueue("6"));


        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
        System.out.println(arrayQueue.deQueue());
    }
}

2.2链式队列

package com.desmond.codebase.algorithm.queue;

/**
 * 链式队列.
 * @author presleyli
 * @date 2019/1/7 10:33 PM
 */
public class LinkedListQueue {

    private Node head;
    private Node tail;

    /**
     * O(1).
     * @param data
     * @return
     */
    public boolean enQueue(String data) {
        if(tail == null) {
            Node node = new Node(data, null);

            tail = node; // 只是把node的首地址给tail
            head = node; // 只是把node的首地址给tail
        } else {
            Node node = new Node(data, null);
            tail.next = node; // 利用tail首地址(指针)找到tail所指的实际堆里的对象,把其对象的next指针指向新的结点node.

            tail = node; // 只是把node的首地址给tail
        }

        printAll();

        return true;
    }

    /**
     * O(1).
     * @return
     */
    public String deQueue() {
        if(head == null) {
            return null;
        }

        String data = head.data;

        if(head.next == null) {
            head = null;
            tail = null;
        } else {
            Node current = head;

            head = head.next;

            current = null;
        }

        printAll();

        return data;
    }

    public void printAll() {
        StringBuilder sb = new StringBuilder();
        for(Node node = head; node != null || node != tail; node = node.next) {
            if(node == null) {
                break;
            }

            sb.append(node.data).append(">>>>");
        }

        System.out.println(sb);
    }

    public static void main(String[] args) {
        LinkedListQueue queue = new LinkedListQueue();

        System.out.println(queue.enQueue("1"));
        System.out.println(queue.enQueue("2"));
        System.out.println(queue.enQueue("3"));
        System.out.println(queue.enQueue("4"));
        System.out.println(queue.enQueue("5"));

        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
    }

    private static class Node {
        private String data;
        private Node next;

        public Node(String data, Node next) {
            this.data = data;
            this.next = next;
        }
    }
}

2.3循环队列

2.3.1 概念

循环队列:

循环队列,顾名思义,它长得像一个环。原本数组是有头有尾的,是一条直线。现在我们把首尾相连,扳成了一个环

最重要的是 队空和队满判定:

队列满条件:head = (tail+1)%n
队列空条件:head=tail

2.3.2 示意图

在这里插入图片描述

2.3.3 代码

package com.desmond.codebase.algorithm.queue;

/**
 * 循环队列:
 * 判断 队列满条件:head = (tail+1)%n <br/>
 * 队列空条件:head=tail <br/>
 * 浪费了一个空间.
 * @author presleyli
 * @date 2019/1/8 7:55 PM
 */
public class CircularQueue {
    private int head;
    private int tail;
    private int n;

    private String[] arr;

    public CircularQueue(int n) {
        this.n = n;
        arr = new String[n];
    }

    /**
     * O(1)
     * @param data
     * @return
     */
    public boolean enQueue(String data) {
        int tmp = (tail + 1)%n; // head = (tail+1)%n
        if(head == tmp) { // 队满条件:  head = (tail+1)%n
            return false;
        }

        arr[tail++] = data;

        tail = tail >= n ? 0 : tail;

        printAll();

        return true;
    }

    /**
     * O(1)
     * @return
     */
    public String deQueue() {
        // 队空 条件: head=tail
        if(head == tail) {
            return null;
        }

        String data = arr[head];

//        head = head + 1;
//        head = head >= n ? 0 : head;
        head = (head + 1) % n;

        printAll();

        return data;
    }

    public void printAll() {
        StringBuilder sb = new StringBuilder();

        if(head < tail) {
            for(int i=head;i<tail;i++) {
                sb.append(arr[i]).append(">>>");
            }
        } else if(head > tail) {
            for(int i=head; i<n; i++) {
                sb.append(arr[i]).append(">>>");
            }

            for(int i=0; i<tail; i++) {
                sb.append(arr[i]).append(">>>");
            }
        }

        System.out.println(sb);
    }

    public static void main(String[] args) {
        CircularQueue queue = new CircularQueue(4);

        System.out.println(queue.enQueue("1"));
        System.out.println(queue.enQueue("2"));
        System.out.println(queue.enQueue("3"));
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());
        System.out.println(queue.deQueue());

        System.out.println(queue.enQueue("5"));
        System.out.println(queue.enQueue("6"));
        System.out.println(queue.enQueue("7"));
        System.out.println(queue.enQueue("8"));
        System.out.println(queue.enQueue("9"));


        System.out.println(queue.deQueue());

    }
}

3.应用

3.1阻塞队列

3.2并发队列

3.3资源池

​ 线程池没有空闲线程时,新的任务请求线程资源时,线程池该如何处理?各种处理策略又是如何实现的呢? 我们一般有两种处理策略。

  • 第一种是非阻塞的处理方式,直接拒绝任务请求;
  • 另一种是阻塞的处理方式,将请求排队,等到有空闲线程时,取出排队的请求继续处理。

​ 那如何存储排队的请求呢? 我们希望公平地处理每个排队的请求,先进者先服务,所以队列这种数据结构很适合来存储排队请求。我们前面说过,队列有基于链表和基于数组这两种实现方式。这两种实现方式对于排队请求又有什么区别呢? 基于链表的实现方式,可以实现一个支持无限排队的无界队列(unbounded queue),但是可能会导致过多的请求排队等待,请求处理的响应时间过长。所以,针对响应时间比较敏感的系统,基于链表实现的无限排队的线程池是不合适的。

​ 而基于数组实现的有界队列(bounded queue),队列的大小有限,所以线程池中排队的请求超过队列大小时,接下来的请求就会被拒绝,这种方式对响应时间敏感的系统来说,就相对更加合理。不过,设置一个合理的队列大小,也是非常有讲究的。队列太大导致等待的请求太多,队列太小会导致无法充分利用系统资源、发挥最大性能。

​ 除了前面讲到队列应用在线程池请求排队的场景之外,队列可以应用在任何有限资源池中,用于排队请求,比如数据库连接池等。实际上,对于大部分资源有限的场景,当没有空闲资源时,基本上都可以通过“队列”这种数据结构来实现请求排队

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值