一、队列(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 packagecom.ietree.basic.datastructure.queue;2
3 importjava.util.Arrays;4
5 /**
6 * Created by ietree7 * 2017/4/298 */
9 public class SequenceQueue{10
11 private int DEFAULT_SIZE = 10;12 //保存数组的长度
13 private intcapacity;14 //定义一个数组用于保存顺序队列的元素
15 privateObject[] elementData;16 //保存顺序队列中元素的当前个数
17 private int front = 0;18 private int rear = 0;19
20 //以默认数组长度创建空顺序队列
21 publicSequenceQueue() {22
23 capacity =DEFAULT_SIZE;24 elementData = newObject[capacity];25
26 }27
28 //以一个初始化元素来创建顺序队列
29 publicSequenceQueue(T element) {30
31 this();32 elementData[0] =element;33 rear++;34
35 }36
37 /**
38 * 以指定长度的数组来创建顺序线性表39 *40 *@paramelement 指定顺序队列中第一个元素41 *@paraminitSize 指定顺序队列底层数组的长度42 */
43 public SequenceQueue(T element, intinitSize) {44
45 this.capacity =initSize;46 elementData = newObject[capacity];47 elementData[0] =element;48 rear++;49 }50
51 /**
52 * 获取顺序队列的大小53 *54 *@return顺序队列的大小值55 */
56 public intlength() {57
58 return rear -front;59
60 }61
62 /**
63 * 插入队列64 *65 *@paramelement 入队列的元素66 */
67 public voidadd(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 publicT 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 returnoldValue;92
93 }94
95 //返回队列顶元素,但不删除队列顶元素
96 publicT element() {97
98 if(empty()) {99 throw new IndexOutOfBoundsException("空队列异常");100 }101 return(T) elementData[front];102
103 }104
105 //判断顺序队列是否为空
106 public booleanempty() {107
108 return rear ==front;109
110 }111
112 //清空顺序队列
113 public voidclear() {114
115 //将底层数组所有元素赋值为null
116 Arrays.fill(elementData, null);117 front = 0;118 rear = 0;119
120 }121
122 publicString 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 packagecom.ietree.basic.datastructure.queue;2
3 /**
4 * Created by ietree5 * 2017/4/306 */
7 public classSequenceQueueTest {8
9 public static voidmain(String[] args) {10
11 SequenceQueue queue = new SequenceQueue();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 packagecom.ietree.basic.datastructure.queue;2
3 /**
4 * Created by ietree5 * 2017/4/306 */
7 public class LinkQueue{8
9 //定义一个内部类Node,Node实例代表链队列的节点
10 private classNode {11
12 //保存节点的数据
13 privateT data;14 //指向下个节点的引用
15 privateNode next;16
17 //无参构造器
18 publicNode() {19 }20
21 //初始化全部属性的构造器
22 publicNode(T data, Node next) {23
24 this.data =data;25 this.next =next;26
27 }28
29 }30
31 //保存该链队列的头节点
32 privateNode front;33 //保存该链队列的尾节点
34 privateNode rear;35 //保存该链队列中已包含的节点数
36 private intsize;37
38 //创建空链队列
39 publicLinkQueue() {40 //空链队列,front和rear的值都为null
41 front = null;42 rear = null;43 }44
45 //以指定数据元素来创建链队列,该链队列只有一个元素
46 publicLinkQueue(T element) {47
48 front = new Node(element, null);49 //只有一个节点,front、rear都是指向该节点
50 rear =front;51 size++;52
53 }54
55 //返回链队列的长度
56 public intlength() {57
58 returnsize;59
60 }61
62 //将新元素加入队列
63 public voidadd(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 publicT remove() {81
82 Node oldfront =front;83 //让front引用指向原队列顶元素的下一个元素
84 front =front.next;85 //释放原队列顶元素的next引用
86 oldfront.next = null;87 size--;88 returnoldfront.data;89
90 }91
92 //访问队列顶元素,但不删除队列顶元素
93 publicT element() {94
95 returnrear.data;96
97 }98
99 //判断链队列是否为空队列
100 public booleanempty() {101
102 return size == 0;103
104 }105
106 //请空链队列
107 public voidclear() {108 //将front、rear两个节点赋为null
109 front = null;110 rear = null;111 size = 0;112 }113
114 publicString 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 packagecom.ietree.basic.datastructure.queue;2
3 /**
4 * Created by ietree5 * 2017/4/306 */
7 public classLinkQueueTest {8
9 public static voidmain(String[] args) {10
11 LinkQueue queue = new LinkQueue("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]