数据结构-----4.队列:

1.特点:队列有“先进先出”的特点,使用的场景多数用于资源池这种,例如:线程池中对等待线程的处理,数据库连接池中对线程的管理

2. 队列的生成有两种方式:(1)基于数组生成,称为顺序队列。(2)基于链表生成,称为链式队列。

3.基于数组生成队列的程序:

(1)在队列中进行入队操作时,tail指针会不断地向后移动,直到数组已经被装满。进行出队操作时,head指针会不断地从0开始向后移动,这样会出现一个情况:(当tail指针移动到最后时,即使数组的0---head区间有位置,也不会承装数据,造成数组资源的浪费),所以我们需要采用 “数据搬移” 的操作。

数据搬移有两种方式:(1)每次有数据入队,便会搬移一次,相当于每次都删除下标为0的数据。这样入队操作的时间复杂对便会从O(1)变成O(n)。(2)只有当tail指针到达最后时,并且head指针不为0,才进行一次整体的数据搬移操作,这样入队操作的平均时间复杂度还是O(1)。

/*
* 基于数组实现的顺序队列*/
public class ArrayQueue {
    /*定义队列中承装数据的数组*/
    private Object[] elementData;

    /*定义队列的容量*/
    private int capacity;

    /*定义队列的头指针和尾指针*/
    private int head;
    private int tail;

    public ArrayQueue(int capacity) {
        this.elementData = new Object[capacity];
        this.capacity = capacity;
        this.head = 0;
        this.tail = 0;
    }

    /*
    * 入队操作*/
    public boolean enQueue(Object element) {
        /*判断当前队列是否已满*/
        if(capacity == tail) return false;
        elementData[tail] = element;
        tail++;
        return true;
    }

    /*
    * 采用数据搬移的方法,使数组中的空闲空间,得以充分的利用*/
    public boolean enQueueMove(Object element) {
        /*如果尾指针tail=capacity && head=0时,表明数组已经装满*/
        if(tail == capacity ) {
            if(head == 0) return false;
            /*如果尾指针tail=capacity,并且head!=0时,进行数据搬移操作*/
            for(int i=head;i<tail;i++) {
                elementData[i-head] = elementData[i];
            }
            //搬移完数据之后,重新设置head,tail的指针
            tail = tail - head;
            head = 0;
        }
        /*如果队列后面还有剩余的位置,那么数据正常加入队尾*/
        elementData[tail] = element;
        tail++;
        return true;
    }

    /*
    * 出队操作*/
    public Object deQueue() {
        /*判断当前队列是否为空*/
        if(tail == head) return null;
        Object element = elementData[head];
        head++;
        return element;
    }

    public static void main(String[] args) {
        ArrayQueue queue = new ArrayQueue(5);
        for(int i=0;i<=5;i++) {
            System.out.println(queue.enQueue(i)+" , "+i);
        }
        for(int i=0;i<=2;i++) {
            System.out.println(queue.deQueue()+" ,出队");
        }
        System.out.println(queue.enQueueMove("chen")+" , chen");
        System.out.println(queue.enQueueMove("chen")+" , chen");
        System.out.println(queue.enQueueMove("chen")+" , chen");
        System.out.println(queue.enQueueMove("chen")+" , chen");
    }
}
/*基于链表生成的队列*/
public class LinkedListQueue<E> {

    /*定义两个指针,head指向队列头部,tail指向队列尾部*/
    private Node head = null;

    private Node tail = null;

    /*入队操作*/
    public void push(E value) {
        Node<E> node = new Node<>(value,null);
        /*tail == null 表示队列中还没有加入元素*/
        if(tail == null) {
            head = node;
            tail = node;
        }else {
            tail.setNext(node);
            tail = tail.getNext();
        }
    }

    /*出队操作*/
    public E pop() {
        if(head == null) return null;
        E value = (E)head.getValue();
        head = head.getNext();
        return value;
    }

    public void printAll() {
        //if(head == null) return;
        while (head != null) {
            System.out.println(head.getValue());
            head = head.getNext();
        }
        return;
    }

    private class Node<E>{

        private E value;

        private Node<E> next;

        public Node(E value,Node<E> next) {
            this.value = value;
            this.next = next;
        }

        public E getValue() {
            return value;
        }

        public void setValue(E value) {
            this.value = value;
        }

        public Node<E> getNext() {
            return next;
        }

        public void setNext(Node<E> next) {
            this.next = next;
        }
    }

    public static void main(String[] args) {
        LinkedListQueue queue = new LinkedListQueue();
        queue.push("1");
        queue.push("2");
        queue.pop();
        queue.push("3");
        queue.push("4");
        queue.pop();
        queue.push("5");
        queue.pop();
        queue.printAll();
    }
}基于数组生成的循环队列,它的优点在于,在队列中删除数据后,空闲的空间可以得到充分的利用,并且不需要进行“搬移数据操作”


/*基于数组生成一个循环队列*/
public class CircularQueue<E> {
    /*循环队列中的内部数组*/
    private Object[] elementData;
    /*循环队列的容量*/
    private int capacity;
    /*循环队列的头指针和尾指针*/
    private int head = 0;
    private int tail = 0;

    public CircularQueue(int capacity) {
        this.elementData = new Object[capacity];
        this.capacity = capacity;
    }

    /*入队操作:
    * 当tail指针指向数组中最后一位时,(tail+1)%capacity == head,最后一位加不上数据,
    * 所以使用循环队列会浪费一个数组空间*/
    public boolean enQueue(E value) {
        /*如果队列满了,返回false*/
        if((tail+1)%capacity == head)
            return false;
        elementData[tail] = value;
        /*因为当前是一个环形队列,所以判断下一位时需要使用(tail+1) % capacity*/
        tail = (tail+1) % capacity;
        return true;
    }

    /*出队操作*/
    public E deQueue() {
        if(head == tail) return null;
        E value = (E)elementData[head];
        head = (head + 1) % capacity;
        return value;
    }

    public void printAll() {
        while ((head+1)%capacity < tail) {
            System.out.println(elementData[head]);
            head = (head+1)%capacity;
        }
        /*因为在while循环中,由于判断的原因,tai指针的前一个元素遍历不到,所以需要另外打印*/
        if((head+1) % capacity == tail) {
            System.out.println(elementData[head]);
        }
    }

    public static void main(String[] args) {
        /*由于在循环队列中,最后一个位置不会承装数据,所以如果定义数组的容量为9,
          那么实际上只能承装8个数据*/
        CircularQueue<String> queue = new CircularQueue<>(9);
        queue.enQueue("1");
        queue.enQueue("2");
        queue.enQueue("3");
        queue.enQueue("4");
        queue.deQueue();
        queue.enQueue("5");
        queue.enQueue("6");
        queue.printAll();
    }
}

阻塞队列:

(1)定义:阻塞队列就是在正常队列的情况下,添加阻塞操作。当队列为空时,从队列获取数据的操作会被阻塞,直到队列中    有数据。当队列满时,向队列添加数据时会被阻塞,直到队列中存在空闲位置。

基于阻塞队列可以实现一个 生产者---消费者模型,并且还可以通过协调生产者和消费者的个数,来提高数据的处理效率。

线程池的底层,也是通过一个队列实现的,当线程池中的线程全部都在工作的时候,当有新的任务请求过来时,就会将任务加入到线程池的队列中,等待线程去执行。

实现队列有两种方式,数据和链表,基于链表实现的队列,是一个没有界限的队列,所以当前任务等待的时间会比较长,对于时间响应敏感的系统来说,不太适合,这时可以选用基于数组实现的队列,可以固定队列的长度,队列装满之后的任务会被拒绝掉,所以系统的响应时间会比较快。

合理的设置队列的容量也是有讲究的,容量太大,会降低系统的响应时间,容量太小,系统的资源得不到充分的利用。实际上对于大部分资源有限的场景,在没有空闲资源时,都可以使用队列这种数据结构来实现请求排队。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值