• 【数据结构】队列与实现分析


     

    概念

     

    (百度百科)队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

    从概念上看,跟栈多少有几分相似之处,同样是特殊的线性代表,同样只能在两端操作,唯一的区别除了名字意外,就是线性结构头和尾操作的那点区别了。栈是一种先进后出的结构,那么队列就是一种先进先出的机构。队列在现实中还算是比较常见的,例如排队就是一种队列结构的“实现”,谁排第一位(先进),谁就先获得优先权(先出),当然,插队是这种不文明现象就不值得一提了。在栈的学习场景中我知道栈分别有循序栈和链表栈,主要的区别在于栈使用的实现结构数组和链表。同理,队列同样可以基于这两种基础结构分别实现静态队列和链表队列,此外还有一个叫循环队列的类别,说白了,跟循环链表的概念差不多,通过首尾相连达到一个循环状的结构。

     

    在学习队列的特性过程中,结合现实的一些场景就可以很好理解了。接下莱看看队列结构的一些主要操作有哪些:

    InitQueue()   ——初始化队列

    EnQueue()      ——进队列

    DeQueue()      ——出队列

    IsQueueEmpty()  ——判断队列是否为空

    IsQueueFull()    ——判断队列是否已满

    以上为队列结构的一些主要操作,再来结合Java语言中ArrayBlockingQueue类对这些操作的实现吧:

    public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable{
        ……
    }
    public abstract class AbstractQueue<E> extends AbstractCollection<E> implements Queue<E> {
        ……
    }
    public interface BlockingQueue<E> extends Queue<E> {
        ……
    }
    public interface Queue<E> extends Collection<E> {
        ……
    }

    从以上ArrayBlockingQueue类的名称和集成关系来看,ArrayBlockingQueue是一个基于数组实现的阻塞队列。再来看看各队列方法的实现:

    1 public ArrayBlockingQueue(int capacity, boolean fair) {
    2   if (capacity <= 0)
    3         throw new IllegalArgumentException();
    4   this.items = (E[]) new Object[capacity];
    5   lock = new ReentrantLock(fair);
    6   notEmpty = lock.newCondition();
    7   notFull =  lock.newCondition();
    8 }

    从ArrayBlockingQueue构造方法可以看出,它定义了一个Object数组和相关锁的实例,这些锁是确保ArrayBlockingQueue的线性安全的。

     1 public boolean offer(E e) {
     2   if (e == null) throw new NullPointerException();
     3   final ReentrantLock lock = this.lock;
     4   lock.lock();
     5   try {
     6   if (count == items.length)
     7        return false;
     8      else {
     9            insert(e);
    10            return true;
    11        }
    12     } finally {
    13         lock.unlock();
    14     }
    15 }

    以上为ArrayBlockingQueue的插入队列尾部元素的方法,它是通过Lock锁的机制实现线性安全的。

     1 public E poll() {
     2     final ReentrantLock lock = this.lock;
     3     lock.lock();
     4     try {
     5     if (count == 0)
     6            return null;
     7         E x = extract();
     8         return x;
     9     } finally {
    10         lock.unlock();
    11     }
    12 }

    以上为ArrayBlockingQueue获取队列头部元素的方法,同样是通过Lock机制实现线性安全。接下来看看offer中的insert(e)和poll()中extract()方法:

     1 private void insert(E x) {
     2   items[putIndex] = x;
     3   putIndex = inc(putIndex);
     4   ++count;
     5   notEmpty.signal();
     6 }
     7 private E extract() {
     8   final E[] items = this.items;
     9   E x = items[takeIndex];
    10   items[takeIndex] = null;
    11   takeIndex = inc(takeIndex);
    12   --count;
    13   notFull.signal();
    14   return x;
    15 }

    从上面两个队列操作方法可以看到,插入是依赖于putIndex数组标签,而取出是依赖于takeIndex数组标签,每插入或取出元素都会对各自标签进行inc()自增,再来看看inc()方法:

    1 final int inc(int i) {
    2     return (++i == items.length)? 0 : i;
    3 }

    显而易见,这是一个循环数组队列,当数组索引达到数组长度最大值,又重新回到数组0位的开始重新循环存放元素,前提队列没有被填满。

  • 相关阅读:
    Smobiler如何实现.net一键开发,ios和android跨平台运行
    使用Smobiler实现类似美团的界面
    疫情当下,企业系统如何快速实现移动化?
    Smobiler针对百度文字识别SDK动态编译与运行
    smobiler自适应不同手机分辨率
    仓库管理移动应用解决方案——C#开发的移动应用开源解决方案
    移动OA办公——Smobiler第一个开源应用解决方案,快来get吧
    react-native 标题随页面滚动显示和隐藏
    react-native 键盘遮挡输入框
    解决adb网络连接中出现的“由于目标计算机积极拒绝,无法连接”错误
  • 原文地址:https://www.cnblogs.com/wcd144140/p/5359312.html
Copyright © 2020-2023  润新知