• Java队列存储结构及实现


    一、队列(Queue)

    队列是一种特殊的线性表,它只允许在表的前段(front)进行删除操作,只允许在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。

    对于一个队列来说,每个元素总是从队列的rear端进入队列,然后等待该元素之前的所有元素出队之后,当前元素才能出对,遵循先进先出(FIFO)原则。

    如果队列中不包含任何元素,该队列就被称为空队列。

    Java提供了一个Queue接口,并为该接口提供了众多的实现类:ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、PriorityQueue、ConcurrentLinkedQueue和SynchronousQueue。

    其中常用的是:ArrayBlockingQueue、LinkedBlockingQueue和CurrentLinkedQueue,它们都是线程安全的队列。LinkedBlockingQueue队列的吞吐量通常比ArrayBlockingQueue队列高,但在大多数并发应用程序中,LinkedBlockingQueue的性能要低。

    除了LinkedBlockingQueue队列之外,JDK还提供了另外一种链队列ConcurrentLinkedQueue,它基于一种先进的、无等待(wait-free)队列算法实现。

    二、顺序队列存储结构的实现

      1 package com.ietree.basic.datastructure.queue;
      2 
      3 import java.util.Arrays;
      4 
      5 /**
      6  * Created by ietree
      7  * 2017/4/29
      8  */
      9 public class SequenceQueue<T> {
     10 
     11     private int DEFAULT_SIZE = 10;
     12     // 保存数组的长度
     13     private int capacity;
     14     // 定义一个数组用于保存顺序队列的元素
     15     private Object[] elementData;
     16     // 保存顺序队列中元素的当前个数
     17     private int front = 0;
     18     private int rear = 0;
     19 
     20     // 以默认数组长度创建空顺序队列
     21     public SequenceQueue() {
     22 
     23         capacity = DEFAULT_SIZE;
     24         elementData = new Object[capacity];
     25 
     26     }
     27 
     28     // 以一个初始化元素来创建顺序队列
     29     public SequenceQueue(T element) {
     30 
     31         this();
     32         elementData[0] = element;
     33         rear++;
     34 
     35     }
     36 
     37     /**
     38      * 以指定长度的数组来创建顺序线性表
     39      *
     40      * @param element  指定顺序队列中第一个元素
     41      * @param initSize 指定顺序队列底层数组的长度
     42      */
     43     public SequenceQueue(T element, int initSize) {
     44 
     45         this.capacity = initSize;
     46         elementData = new Object[capacity];
     47         elementData[0] = element;
     48         rear++;
     49     }
     50 
     51     /**
     52      * 获取顺序队列的大小
     53      *
     54      * @return 顺序队列的大小值
     55      */
     56     public int length() {
     57 
     58         return rear - front;
     59 
     60     }
     61 
     62     /**
     63      * 插入队列
     64      *
     65      * @param element 入队列的元素
     66      */
     67     public void add(T element) {
     68 
     69         if (rear > capacity - 1) {
     70             throw new IndexOutOfBoundsException("队列已满异常");
     71         }
     72         elementData[rear++] = element;
     73 
     74     }
     75 
     76     /**
     77      * 移除队列
     78      *
     79      * @return 出队列的元素
     80      */
     81     public T remove() {
     82 
     83         if (empty()) {
     84             throw new IndexOutOfBoundsException("空队列异常");
     85         }
     86 
     87         // 保留队列的rear端的元素的值
     88         T oldValue = (T) elementData[front];
     89         // 释放队列顶元素
     90         elementData[front++] = null;
     91         return oldValue;
     92 
     93     }
     94 
     95     // 返回队列顶元素,但不删除队列顶元素
     96     public T element() {
     97 
     98         if (empty()) {
     99             throw new IndexOutOfBoundsException("空队列异常");
    100         }
    101         return (T) elementData[front];
    102 
    103     }
    104 
    105     // 判断顺序队列是否为空
    106     public boolean empty() {
    107 
    108         return rear == front;
    109 
    110     }
    111 
    112     // 清空顺序队列
    113     public void clear() {
    114 
    115         // 将底层数组所有元素赋值为null
    116         Arrays.fill(elementData, null);
    117         front = 0;
    118         rear = 0;
    119 
    120     }
    121 
    122     public String toString() {
    123 
    124         if (empty()) {
    125 
    126             return "[]";
    127 
    128         } else {
    129 
    130             StringBuilder sb = new StringBuilder("[");
    131             for (int i = front; i < rear; i++) {
    132                 sb.append(elementData[i].toString() + ", ");
    133             }
    134             int len = sb.length();
    135             return sb.delete(len - 2, len).append("]").toString();
    136         }
    137 
    138     }
    139 
    140 }

    测试类:

     1 package com.ietree.basic.datastructure.queue;
     2 
     3 /**
     4  * Created by ietree
     5  * 2017/4/30
     6  */
     7 public class SequenceQueueTest {
     8 
     9     public static void main(String[] args) {
    10 
    11         SequenceQueue<String> queue = new SequenceQueue<String>();
    12         // 依次将4个元素加入到队列中
    13         queue.add("aaaa");
    14         queue.add("bbbb");
    15         queue.add("cccc");
    16         queue.add("dddd");
    17         System.out.println(queue);
    18 
    19         System.out.println("访问队列的front端元素:" + queue.element());
    20 
    21         System.out.println("第一次弹出队列的front端元素:" + queue.remove());
    22 
    23         System.out.println("第二次弹出队列的front端元素:" + queue.remove());
    24 
    25         System.out.println("两次remove之后的队列:" + queue);
    26     }
    27 
    28 }

    程序输出:

    [dddd, cccc, bbbb, aaaa]
    访问栈顶元素:dddd
    第一次弹出栈顶元素:dddd
    第二次弹出栈顶元素:cccc
    两次pop之后的栈:[bbbb, aaaa]

    三、队列的链式存储结构实现

      1 package com.ietree.basic.datastructure.queue;
      2 
      3 /**
      4  * Created by ietree
      5  * 2017/4/30
      6  */
      7 public class LinkQueue<T> {
      8 
      9     // 定义一个内部类Node,Node实例代表链队列的节点
     10     private class Node {
     11 
     12         // 保存节点的数据
     13         private T data;
     14         // 指向下个节点的引用
     15         private Node next;
     16 
     17         // 无参构造器
     18         public Node() {
     19         }
     20 
     21         // 初始化全部属性的构造器
     22         public Node(T data, Node next) {
     23 
     24             this.data = data;
     25             this.next = next;
     26 
     27         }
     28 
     29     }
     30 
     31     // 保存该链队列的头节点
     32     private Node front;
     33     // 保存该链队列的尾节点
     34     private Node rear;
     35     // 保存该链队列中已包含的节点数
     36     private int size;
     37 
     38     // 创建空链队列
     39     public LinkQueue() {
     40         // 空链队列,front和rear的值都为null
     41         front = null;
     42         rear = null;
     43     }
     44 
     45     // 以指定数据元素来创建链队列,该链队列只有一个元素
     46     public LinkQueue(T element) {
     47 
     48         front = new Node(element, null);
     49         // 只有一个节点,front、rear都是指向该节点
     50         rear = front;
     51         size++;
     52 
     53     }
     54 
     55     // 返回链队列的长度
     56     public int length() {
     57 
     58         return size;
     59 
     60     }
     61 
     62     // 将新元素加入队列
     63     public void add(T element) {
     64         // 如果该链队列还是空链队列
     65         if (front == null) {
     66             front = new Node(element, null);
     67             // 只有一个节点,front、rear都是指向该节点
     68             rear = front;
     69         } else {
     70             // 创建新节点
     71             Node newNode = new Node(element, null);
     72             // 让尾节点的next指向新增的节点
     73             rear.next = newNode;
     74             rear = newNode;
     75         }
     76         size++;
     77     }
     78 
     79     // 删除队列front端的元素
     80     public T remove() {
     81 
     82         Node oldfront = front;
     83         // 让front引用指向原队列顶元素的下一个元素
     84         front = front.next;
     85         // 释放原队列顶元素的next引用
     86         oldfront.next = null;
     87         size--;
     88         return oldfront.data;
     89 
     90     }
     91 
     92     // 访问队列顶元素,但不删除队列顶元素
     93     public T element() {
     94 
     95         return rear.data;
     96 
     97     }
     98 
     99     // 判断链队列是否为空队列
    100     public boolean empty() {
    101 
    102         return size == 0;
    103 
    104     }
    105 
    106     // 请空链队列
    107     public void clear() {
    108         // 将front、rear两个节点赋为null
    109         front = null;
    110         rear = null;
    111         size = 0;
    112     }
    113 
    114     public String toString() {
    115 
    116         // 链队列为空队列时
    117         if (empty()) {
    118             return "[]";
    119         } else {
    120             StringBuilder sb = new StringBuilder("[");
    121             for (Node current = front; current != null; current = current.next) {
    122                 sb.append(current.data.toString() + ", ");
    123             }
    124             int len = sb.length();
    125             return sb.delete(len - 2, len).append("]").toString();
    126         }
    127 
    128     }
    129 
    130 }

    测试类:

     1 package com.ietree.basic.datastructure.queue;
     2 
     3 /**
     4  * Created by ietree
     5  * 2017/4/30
     6  */
     7 public class LinkQueueTest {
     8 
     9     public static void main(String[] args) {
    10 
    11         LinkQueue<String> queue = new LinkQueue<String>("aaaa");
    12         // 依次将4个元素加入到队列中
    13         queue.add("bbbb");
    14         queue.add("cccc");
    15         queue.add("dddd");
    16         System.out.println(queue);
    17 
    18         // 删除一个元素后
    19         queue.remove();
    20         System.out.println("删除一个元素后的队列:" + queue);
    21 
    22         // 再添加一个元素
    23         queue.add("eeee");
    24         System.out.println("再次添加元素后的队列:" + queue);
    25 
    26     }
    27 
    28 }

    程序输出:

    [aaaa, bbbb, cccc, dddd]
    删除一个元素后的队列:[bbbb, cccc, dddd]
    再次添加元素后的队列:[bbbb, cccc, dddd, eeee]
  • 相关阅读:
    Windows10右键添加“在此处打开命令窗口"
    赋值简单理解
    应用 EditPlus 配置 Java 编译环境
    进程和线程的区别
    Java栈与堆
    进程与线程的简单解释
    java的多态性(二)
    内部类详解(很详细)
    java的super和this关键字用法总结
    Java类成员(成员变量和方法)的覆盖与隐藏归纳
  • 原文地址:https://www.cnblogs.com/Dylansuns/p/6789161.html
Copyright © 2020-2023  润新知