隊(duì)列定義
先進(jìn)先出(FIFO)——先進(jìn)隊(duì)列的元素先出隊(duì)列。來源于我們生活中的隊(duì)列(先排隊(duì)的先辦完事)。
基本操作
- initQueue() ——初始化隊(duì)列
- enqueue() ——進(jìn)隊(duì)列
- dequeue() ——出隊(duì)列
- isEmpty() ——判斷隊(duì)列是否為空
- size() ——判斷隊(duì)列中元素的數(shù)量
- isFull() -- 判斷隊(duì)列是否已滿:僅在設(shè)定了隊(duì)列的最大容量時(shí)有效
隊(duì)列可以由數(shù)組和鏈表兩種形式實(shí)現(xiàn)隊(duì)列操作(java語言)本文將分別實(shí)現(xiàn)這兩種隊(duì)列。
一、鏈隊(duì)列——隊(duì)列的鏈?zhǔn)奖硎竞蛯?shí)現(xiàn):
功能分析:
- 這里,我們將隊(duì)列表示為一條從最早插入的元素到最近插入的元素的鏈表,實(shí)例變量first執(zhí)行隊(duì)列的開頭,實(shí)例變量last指向隊(duì)列的結(jié)尾。
- 一個元素入列時(shí),我們將它添加到鏈表尾部,為空時(shí)需要額外處理:first和last同時(shí)指向第一個元素。
- 一個元素出列時(shí),我們刪除鏈表的尾部元素。
- size:在實(shí)例內(nèi)部持有一個私有屬性保存這個值。
- isEmpty:當(dāng)size為0時(shí),表示為空。
使用鏈表可以達(dá)到的效果:
它可以處理任意類型的數(shù)據(jù)(使用泛型),所需的空間總是和集合的大小成正比,操作所需要的時(shí)間總是和集合的大小無關(guān)。
代碼實(shí)現(xiàn):
/**
*
* @Created on 2017-02-27 12:19
* 隊(duì)列接口表示
*/
public interface FlowerQueue<T> {
/**
* 初始化隊(duì)列: 設(shè)定當(dāng)前隊(duì)列的最大容量,如果需要的話。
*/
void initQueue(int maxSize);
/**
* 進(jìn)入隊(duì)列
*/
void enqueue(T item);
/**
* 出隊(duì)列
* @return
*/
T dequeue();
int size();
boolean isEmpty();
/**
* 是否已經(jīng)不再允許添加新的元素
* @return
*/
boolean isFull();
}
/**
*
* @Created on 2017-02-27 12:26
* 鏈表實(shí)現(xiàn)的隊(duì)列
*/
public class FlowerLinkedQueue<T> implements FlowerQueue<T> {
private int size;
private int maxSize;
private Node<T> first;
private Node<T> last;
public FlowerLinkedQueue() {
initQueue(16);
}
@Override
public void initQueue(int maxSize) {
this.maxSize = maxSize;
first = null;
last = null;
}
@Override
public void enqueue(T item) {
if (size() == maxSize) {
throw new RuntimeException("已經(jīng)達(dá)到當(dāng)前鏈表的最大容量");
}
Node<T> oldLast = last;
last = new Node<T>();
last.item = item;
last.next = null;
// 如果是第一個元素,需要將first指向last
if (isEmpty()) {
first = last;
} else {
oldLast.next = last;
}
size++;
}
@Override
public T dequeue() {
if (isEmpty()) {
return null;
}
T item = first.item;
if (first.next == null) {
first = null;
last = null;
} else {
first = first.next;
}
size--;
return item;
}
@Override
public int size() {
return this.size;
}
@Override
public boolean isEmpty() {
return this.size == 0;
}
@Override
public boolean isFull() {
return this.size == maxSize;
}
// 定義一個內(nèi)部類, 作為鏈表結(jié)構(gòu)
private class Node<T> {
T item;
Node next;
}
}
/**
*
* @Created on 2017-02-27 17:20
* 鏈表實(shí)現(xiàn)的隊(duì)列測試用例
*/
public class FlowerLinkedQueueTest {
@Test
public void test() {
FlowerLinkedQueue<Integer> queue = new FlowerLinkedQueue<Integer>();
for(int i=0; i<100; i++) {
if (i < 16) {
queue.enqueue(i);
} else {
Integer dequeue = queue.dequeue();
System.out.println("出隊(duì)列的數(shù)值:" + dequeue);
}
System.out.println("當(dāng)前隊(duì)列長度:" + queue.size());
}
}
}
二、數(shù)組隊(duì)列-底層為數(shù)組的隊(duì)列:
這種方式,底層使用的是數(shù)組來存儲數(shù)據(jù),然后通過2個指針來控制入隊(duì)和出隊(duì)。
功能分析:
- 首先定義一個固定長度的數(shù)組。
- 定義兩個指針,front代表隊(duì)頭,rear代表隊(duì)尾。
- 隨著元素不斷的入隊(duì)和出隊(duì),會出現(xiàn)一種情況:數(shù)組還沒滿,但是rear就要越界了。因此我們需要考慮使用循環(huán)數(shù)組。
- 所謂循環(huán)數(shù)組,就當(dāng)rear出現(xiàn)越界情況時(shí),對其進(jìn)行取模,從而使新數(shù)據(jù)放到數(shù)組索引為0的位置,直到整個數(shù)組被放滿。
- 當(dāng)數(shù)組中的每個索引處都有值,又有新元素入隊(duì)時(shí),需要對數(shù)組進(jìn)行動態(tài)擴(kuò)容:新建一個數(shù)組,將原數(shù)組的數(shù)據(jù)拷貝過來。
代碼實(shí)現(xiàn):
實(shí)現(xiàn)類:
/**
*
* @Created on 2017-02-27 19:12
* 基于數(shù)組實(shí)現(xiàn)的隊(duì)列
*/
public class FlowerArrayQueue<T> implements FlowerQueue<T> {
private T[] data;
public int size;
public int front;
public int rear;
private int capacity = 10;
public FlowerArrayQueue() {
initQueue(capacity);
}
@Override
public void initQueue(int maxSize) {
// 初始化操作
data = (T[]) new Object[maxSize];
size = 0;
}
@Override
public void enqueue(T item) {
// 擴(kuò)容
if (size == data.length) {
// capacity = 2 * capacity
if (rear == 0) {
T[] bigger = (T[]) new Object[data.length * 2];
for (int i = front; i < data.length - front; i++) {
bigger[i] = data[i];
}
bigger[data.length] = item;
rear = data.length;
capacity = 2 * capacity;
front = 0;
data = bigger;
} else {
// capacity = 2 * capacity
T[] bigger = (T[]) new Object[data.length * 2];
for (int i = front; i < data.length - front + 1; i++) {
bigger[i - front] = data[i];
}
for (int i = 0; i < rear; i++) {
bigger[i + data.length - 1] = data[i];
}
data = bigger;
front = 0;
rear = data.length;
capacity = 2 * capacity;
}
}
if (size == 0) {
front = 0;
rear = 0;
}
data[rear] = item;
// 新增到隊(duì)尾時(shí),注意使用循環(huán)數(shù)組避免越界
rear = (rear + 1) % capacity;
size++;
}
@Override
public T dequeue() {
if (size == 0) {
return null;
}
T e = data[front];
data[front] = null;
// 隊(duì)首取出后,注意使用循環(huán)數(shù)組避免越界
front = (front + 1) % capacity;
size--;
return e;
}
@Override
public int size() {
return this.size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean isFull() {
return size == capacity;
}
}
測試用例:
/**
*
* @Created on 2017-02-27 19:36
* 基于數(shù)組的隊(duì)列結(jié)構(gòu) 測試用例
*/
public class FlowerArrayQueueTest {
@Test
public void test() {
FlowerArrayQueue<Integer> queue = new FlowerArrayQueue<Integer>();
for(int i=0; i<100; i++) {
queue.enqueue(i);
System.out.println("當(dāng)前隊(duì)列長度:" + queue.size());
}
for(int i=0; i<200; i++) {
Integer dequeue = queue.dequeue();
System.out.println("當(dāng)前出隊(duì)元素:" + dequeue);
System.out.println("當(dāng)前隊(duì)列長度:" + queue.size());
}
}
}