【数据结构和算法】之队列
一、概念
先进者先出,这就是典型的“队列”。
二、队列和栈
队列跟栈一样,也是一种操作受限的线性表数据结构。

三、队列的种类和队列的实现
- 顺序队列:用数组实现的队列 (代码实现的关键点:确定好队空和队满的判定条件)
当前队列中的数据为: 队头>h->i->j->队尾

向队列中依次添加a,b元素后,队列的数据信息:队头>h->i->j->a->b->队尾

- 链式队列:用链表实现的队列

1、循环队列(尾进头出)
循环对列判断队空的条件:head==tail
循环队列队满的条件:(tail+1)%n=head [队列会空一格位置]

数组方式一(普通队列)
public class CircularQueue { // 数组:items,数组大小:n private String[] items; private int n = 0; // head表示队头下标,tail表示队尾下标 private int head = 0; private int tail = 0; // 申请一个大小为capacity的数组 public CircularQueue(int capacity) { items = new String[capacity]; n = capacity; } // 入队 public boolean enqueue(String item) { // 队列满了 if ((tail + 1) % n == head) return false; items[tail] = item; tail = (tail + 1) % n; return true; } // 出队 public String dequeue() { // 如果head == tail 表示队列为空 if (head == tail) return null; String ret = items[head]; head = (head + 1) % n; return ret; } }
使用锁的条件实现阻塞队列-数组
package obj.sf; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ProducerAndConsumer { public static void main(String[] args) { MyQueue<Integer> myQueue = new MyQueue<>(11); ProducerThread producerThread = new ProducerThread(myQueue); ConsumerThread consumerThread = new ConsumerThread(myQueue); producerThread.start(); consumerThread.start(); } } class ProducerThread extends Thread { private MyQueue myQueue; private int product = 0; public ProducerThread(MyQueue myQueue) { this.myQueue = myQueue; } @Override public void run() { while (product < 30) { myQueue.putData(product); System.out.println("【生产者】生产数据" + product); product++; try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } class ConsumerThread extends Thread { private MyQueue myQueue; private int product = 0; public ConsumerThread(MyQueue myQueue) { this.myQueue = myQueue; } @Override public void run() { while (product < 100) { Object data = myQueue.takeData(); System.out.println("===========【消费者】消费数据" + data); try { Thread.sleep(10000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } class MyQueue<T> { private Object[] dataArray; private int capacity; private int count; private Lock lock; private Condition notFullCondition; private Condition notEmptyCondition; private int headIndex; private int tailIndex; private int arrayLength; public MyQueue(int capacity) { //step1:参数校验 if (capacity <= 0) { throw new IllegalArgumentException("入参异常"); } //step2:初始化存储空间 this.capacity = capacity; this.count = 0; this.dataArray = new Object[this.capacity + 1]; this.tailIndex = this.headIndex = 0; //step3:初始化锁 this.lock = new ReentrantLock(); this.notEmptyCondition = lock.newCondition(); this.notFullCondition = lock.newCondition(); this.arrayLength = this.dataArray.length; } /** * 放入队列 * * @param data * @param <T> */ public <T> void putData(T data) { this.lock.lock(); try { //step1:校验队列是否满 int nextTailIndex = calculateNextIndex(this.tailIndex); while (nextTailIndex == this.headIndex) { //满了,阻塞生产者 try { this.notFullCondition.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } nextTailIndex = calculateNextIndex(this.tailIndex); } //step2:放入数据 this.dataArray[nextTailIndex] = data; this.count++; //step3:更新指针 this.tailIndex = nextTailIndex; //step4:唤醒消费者 this.notEmptyCondition.signalAll(); } finally { this.lock.unlock(); } } /** * 取出队列 * * @param <T> * @return */ public <T> T takeData() { Object data = null; this.lock.lock(); try { //step1:校验队列是否为空 while (this.headIndex == this.tailIndex) { //为空,阻塞消费者 try { this.notEmptyCondition.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //step2:取出数据 int nextHeadIndex = calculateNextIndex(this.headIndex); data = this.dataArray[nextHeadIndex]; //step3:更新指针 this.headIndex = nextHeadIndex; //step4:唤醒生产者 this.notFullCondition.signalAll(); } finally { this.lock.unlock(); } return (T) data; } public int calculateNextIndex(int index) { return (index + 1) % this.arrayLength; } }
2、阻塞队列(线程安全)


数组方式一(阻塞并发队列)
/** * 队列的规则:尾巴进度,头节点出队 * 判断队列是否为空: headIndex == tailIndex * 判断队列是否已经满了:(tailIndex+1) % tab.length == headIndex **/ public class ArrayQueue { public static void main(String[] args) { ArrayQueue arrayQueue = new ArrayQueue(10); arrayQueue.addData(1); arrayQueue.addData(2); arrayQueue.addData(3); arrayQueue.addData(4); arrayQueue.addData(5); arrayQueue.addData(6); arrayQueue.addData(7); arrayQueue.addData(8); arrayQueue.addData(9); arrayQueue.addData(10); arrayQueue.pullData(); arrayQueue.addData(11); for(int i=0;i<10;i++){ System.out.println(arrayQueue.pullData()); } } private final Object lock = new Object(); private int count; private int maxSize; private int[] tab; private int headIndex; private int tailIndex; public ArrayQueue(int size) { this.count = 0; this.maxSize = size; this.tab = new int[size + 1]; } /** * 下一个将要插入元素的位置 * * @return额 */ public int nextInsertIndex() { return (this.tailIndex + 1) % this.tab.length; } /** * 添加一个元素 * * @param data */ public void addData(int data) { synchronized (lock) { //判断队列是否已经满了 while (nextInsertIndex() == headIndex) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //设置元素 tab[this.tailIndex] = data; this.tailIndex++; this.count++; //唤醒线程 lock.notifyAll(); } } /** * 取出一个元素 * * @return */ public int pullData() { synchronized (lock) { //如果头指针和尾巴指针在一个位置上,则表示队里为空,需要等待 while (this.headIndex == this.tailIndex) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //取出元素 int result = tab[headIndex]; this.headIndex++; this.count--; //唤醒等待添加元素的线程 lock.notifyAll(); return result; } } }
链表方式二(阻塞并发队列)
/** * 尾巴进队,头节点出队 * 判断队列已满:队列数据个数== 最大数 * 判断队列已经空:头节点=尾巴节点 * 取数据时判断队列为空:头节点.next.next==null **/ public class LinkQueue { public static void main(String[] args) { LinkQueue linkQueue = new LinkQueue(10); linkQueue.putData(1); linkQueue.putData(2); linkQueue.putData(3); linkQueue.putData(4); linkQueue.putData(5); linkQueue.putData(6); linkQueue.putData(7); linkQueue.putData(8); linkQueue.putData(9); linkQueue.putData(10); linkQueue.pullData(); linkQueue.putData(11); for(int i=0;i<10;i++){ System.out.println(linkQueue.pullData()); } } private final Node tag = new Node(-1); private final Object lock = new Object(); private Node head; private Node tail; private int max; private int count; public LinkQueue(int capacity) { this.max = capacity; this.head = this.tail = tag; this.count = 0; } /** * 放入一个数据 * * @param value */ public void putData(int value) { synchronized (lock) { //step1:判断队列是否已经满了 while (this.count == this.max) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //step2:添加元素 Node waitInsertNode = new Node(value); if (this.tail == this.head) { //表示队列为空 this.head.nexNode = waitInsertNode; waitInsertNode.preNode = this.head; this.tail = waitInsertNode; } else { waitInsertNode.preNode = this.tail; this.tail.nexNode = waitInsertNode; this.tail = waitInsertNode; } this.count++; this.lock.notifyAll(); } } /** * 取出一个数据 * * @return */ public int pullData() { synchronized (lock) { //step1:判断队列是否为空队列 while (this.tail == this.head) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //step2:取出数据 Node result = this.head.nexNode; int value = result.value; Node nexTag = result.nexNode; result.preNode = null; this.count--; if (nexTag != null) { //队列中还有其他元素 nexTag.preNode = this.head; this.head.nexNode = nexTag; } else { //队列中没有元素 this.head.nexNode = null; this.tail = this.head; } //step3:唤醒其他线程 this.lock.notifyAll(); return value; } } private static class Node { private Node nexNode; private Node preNode; private int value; public Node(int value) { this.value = value; } } }
浙公网安备 33010602011771号