• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

无信不立

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【数据结构和算法】之队列

一、概念

先进者先出,这就是典型的“队列”。

 

二、队列和栈

队列跟栈一样,也是一种操作受限的线性表数据结构。

三、队列的种类和队列的实现

  • 顺序队列:用数组实现的队列 (代码实现的关键点:确定好队空和队满的判定条件)

当前队列中的数据为: 队头>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;
        }
    }
View Code

使用锁的条件实现阻塞队列-数组 

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;
    }
}
View Code

 

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;
        }
    }
}
View Code

链表方式二(阻塞并发队列) 

/**
 * 尾巴进队,头节点出队
 * 判断队列已满:队列数据个数== 最大数
 * 判断队列已经空:头节点=尾巴节点
 * 取数据时判断队列为空:头节点.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;
        }
    }

}
View Code

 

posted on 2020-07-12 17:40  无信不立  阅读(107)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3