佇列的幾種實現方式
佇列簡介:
佇列是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作,和棧一樣,佇列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。
佇列是一種最常用的資料結構,也是最重要的一種資料結構,這裡介紹三種實現佇列的方法:
1.基於連結串列來實現佇列。
2.使用linkedList來實現佇列。
3.使用兩個棧來實現一個佇列。
1.首先說第一種實現方式,基於連結串列來實現佇列:
首先新增一個節點類,作為佇列中的節點元素
public class Node { //連結串列中的一個節點 Node next = null; int data; //建構函式,用於新增連結串列時候使用 public Node(int d) { this.data = d; }; }
再新建一個類作為我們的佇列,在該類中實現佇列的入隊和出隊以及求佇列的長度和判斷佇列是否為空等方法
①.入隊操作:
首先通過函式引數傳入要入隊的資料,根據傳入的引數,新增一個節點Node,在入隊方法中判斷該佇列是否為空,若該佇列為空(head==tail),則該入隊的節點既是隊頭也是隊尾。若佇列不為空,則將尾節點tail的next指標指向該元素,然後將tail節點指向該節點。
public void put(Integer data) { Node newNode = new Node(data); //構造一個新節點 if(head == null && tail == null) { //佇列為空 head = newNode; tail = newNode; }else { tail.next = newNode; tail = newNode; } }
②.出隊操作:
若佇列為空,則返回空。若佇列不為空,則返回該佇列的頭結點,然後將頭結點的下一個元素重新作為頭節點
public Integer pop() {
if(this.isEmpty()) {
return null;
}
int data = head.data;
head = head.next;
return data;
}
③.判斷佇列空和對列長度很簡單,直接貼程式碼,不再多說。
public int size() { int count = 0; Node tmp = head; while(tmp != null) { count++; tmp = tmp.next; } return count; }
④.詳細程式碼實現:
package com.wp.datastruct;
/**
* 利用連結串列來實現佇列
* */
public class MyQueue<E> {
Node head = null; //佇列頭
Node tail = null; //佇列尾
/**
* 入隊操作:
* 若該佇列尾空,則入隊節點既是頭結點也是尾節點
* 若佇列不為空,則先用tail節點的next指標指向該節點
* 然後將tail節點指向該節點
* */
public void put(Integer data) {
Node newNode = new Node(data); //構造一個新節點
if(head == null && tail == null) { //佇列為空
head = newNode;
tail = newNode;
}else {
tail.next = newNode;
tail = newNode;
}
}
/**
* 判斷佇列是否為空:當頭結點等於尾節點的時候該佇列就為空
* */
public boolean isEmpty() {
return head == tail;
}
/**
* 出隊操作:
* 若佇列為空,則返回null
* 否則,返回佇列的頭結點,並將head節點指向下一個
* */
public Integer pop() {
if(this.isEmpty()) {
return null;
}
int data = head.data;
head = head.next;
return data;
}
public int size() {
int count = 0;
Node tmp = head;
while(tmp != null) {
count++;
tmp = tmp.next;
}
return count;
}
}
2.使用linkedList來實現佇列
該方法是使用java中的linkedList集合來實現一個佇列,通過呼叫linkedList中的方法來實現佇列的入隊出隊,判空等操作
首先new一個類來作為我們的佇列,該類中包含兩個屬性,一個是size:用來統計該佇列的長度,另一個是LinkedList物件,
代表我們的佇列。
private LinkedList<E> list = new LinkedList<>();
private int size = 0; //用於統計佇列的長度
①.入隊操作:
應為linkedList集合中已經實現好了新增刪除操作,在這裡我們只需要簡單的呼叫方法就可以實現佇列的相關操作了,非常簡單而且容易理解。
public synchronized void put(E data) { //保證執行緒安全,實現同步操作
list.add(data);
size++;
}
②.出隊操作:
public synchronized E pop() {
size--;
return list.removeFirst(); //從頭取出
}
③.詳細程式碼:
public class MyQueue2<E> {
private LinkedList<E> list = new LinkedList<>();
private int size = 0; //用於統計佇列的長度
public synchronized void put(E data) { //保證執行緒安全,實現同步操作
list.add(data);
size++;
}
public synchronized E pop() {
size--;
return list.removeFirst(); //從頭取出
}
public synchronized int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
}
3.使用兩個棧來實現一個佇列。
也可以使用兩個實現好的棧來實現一個佇列(這個問題可能面試筆試的時候回被問到)。
實現方法是:
建立兩個棧s1,s2。入隊的時候就只壓棧到s1中。
出隊分兩種情況:1.當s2不為空的使用,就彈出棧頂元素作為出隊元素。
2.當s2等於空,則先將s1中的元素全部彈出到s2中,再從s2中彈出棧頂元素作為出隊元素。
①.入隊:
public synchronized void put(E data) { //使用同步處理,保證執行緒安全
s1.push(data);
}
②.出隊:
public synchronized E pop() {
if(!s2.isEmpty()) {
return s2.pop();
}else {
s2.push(s1.pop());
return s2.pop();
}
}
③.詳細程式碼實現:
package com.wp.datastruct;
import java.util.Stack;
/**
* 利用兩個棧來模擬佇列操作
* 入隊操作就只是想棧s1中新增,
* 出棧操作分為兩部分:
* 1.當s2中不為空的時候,就直接彈出s2中的棧頂資料
* 2.當s2中為空的時候,就先把s1中的資料全部彈出到s2中然後將棧頂資料出棧
*
* */
public class MyQueue3<E> {
Stack<E> s1 = new Stack<>();
Stack<E> s2 = new Stack<>();
public synchronized void put(E data) { //使用同步處理,保證執行緒安全
s1.push(data);
}
public synchronized E pop() {
if(!s2.isEmpty()) {
return s2.pop();
}else {
s2.push(s1.pop());
return s2.pop();
}
}
public synchronized boolean isEmpty() {
return s1.isEmpty() && s2.empty();
}
}