隊列的設計與實現及應用
一、目的和要求:
(1)正確定義隊列(順序隊或鏈隊);
(2)掌握隊列基本操作實現方法;
(3)能正確分析算法的時間復雜度;
(3)采用隊列解決實際問題。
二、實驗原理及內容:
(1)定義隊列(順序隊列或鏈隊列);
(2)隊列基本操作實現方法;
(3)采用隊列解決實際問題(銀行排隊叫號服務)。
三、實驗步驟:(以鏈隊列為例實現,也可以自行采用順序隊列實現)
(1)定義鏈隊列;
(2)鏈隊列基本操作實現方法;
(3)采用鏈隊列解決銀行排隊叫號服務問題。
四、實驗過程
1、工程結構如下圖所示:
2、隊列接口定義:IStack.java
public interface IQueue<E> {
boolean in(E item);//入隊列操作
E out(); //出隊列操作
E head(); //取對頭元素
int size();//求隊列的長度
boolean isEmpty();//判斷隊列是否為空
boolean isFull();//判斷隊列是否為滿
void clear();//清空隊列
}
3、順序隊列的定義及實現:SeqQueue.java
import java.lang.reflect.Array;
public class SeqQueue<E> implements IQueue<E> {
private int maxsize; //隊列的容量
private E[]data; // 存儲循環順序隊列中的數據元素
private int front; // 指示最近一個己經離開隊列的元素所占的位置
private int rear; // 指示最近一個進行入隊列的元素的位置
private int size;
public int getMaxsize() {
returnmaxsize;
}
public void setMaxsize(int maxsize) {
this.maxsize = maxsize;
}
public E[] getData() {
returndata;
}
public void setData(E[] data) {
this.data = data;
}
public int getFront() {
returnfront;
}
public void setFront(int front) {
this.front = front;
}
public int getRear() {
returnrear;
}
public void setRear(int rear) {
this.rear = rear;
}
//初始化隊列
@SuppressWarnings("unchecked")
public SeqQueue(Class<E> type,int maxsize) {
data = (E[]) Array.newInstance(type,maxsize);
this.maxsize = maxsize;
}
//入隊列操作
public boolean in(E item) {
if(isFull())return false;
data[rear] = item;
rear = (rear+1)%maxsize;
size++;
return true;
}
public int getSize() {
returnsize;
}
public void setSize(int size) {
this.size = size;
}
//出隊列操作
public E out() {
if(isEmpty())
return null;
E i = data[front];
front = (front + 1)%maxsize;
size--;
return i;
}
//取對頭元素
public E head() {
if(isEmpty())
return null;
return
data[front];
}
//求隊列的長度
public int size() {
return (rear+maxsize-front)%maxsize;
}
// 判斷隊列是否為空
public boolean isEmpty() {
if(front ==rear)
return true;
return false;
}
// 判斷循環順序隊列是否為滿
public boolean isFull() {
if(size ==maxsize)
return true;
return false;
}
//清空隊列
public void clear() {
size =0;
front = rear = 0;
}
}
4、順序隊列的測試:TestQueue.java
public class TestQueue {
public static void main(String[] args) {
int[] data={23,45,3,7,6,945};
//注意給定的循環隊列長度至少要比實際長度大1
IQueue<Integer> queue=new SeqQueue<Integer>(Integer.class,data.length+1);
//IQueue<Integer> queue=new LinkQueue<Integer>();
//入隊操作
System.out.println("*******入隊操作*******");
for(int i=0; i<data.length;i++){
queue.in(data[i]);
System.out.println(data[i]+"入隊");
}
int size=queue.size();
//出隊操作
System.out.println("*******出隊操作*******");
for(int i=0; i<size;i++){
System.out.println(queue.out()+"出隊 ");
}
}
}
5、鏈隊結點的定義
class QueueNode<E>
{
private Edata; // 數據域
private QueueNode<E> next; // 引用域
//get和set方法
public E getData() {
returndata;
}
public void setData(E data) {
this.data = data;
}
public QueueNode<E> getNext() {
returnnext;
}
public void setNext(QueueNode<E> next) {
this.next = next;
}
//構造函數
public QueueNode(){}
public QueueNode(E data) {
this.data = data;
}
public QueueNode(E data,QueueNode<E> next) {
this.data = data;
this.next = next;
}
}
6、鏈隊的定義及實現
public class LinkQueue<E> implements IQueue<E> {
private QueueNode<E>front; // 隊列頭指示器
private QueueNode<E>rear; // 隊列尾指示器
private int size; // 隊列數據元素個數
// 初始化鏈隊列
public LinkQueue() {
front = rear = null;
size = 0;
}
// 入隊列操作
public boolean in(E item) {
QueueNode<E> q = new QueueNode<E>(item);
if(front ==null)
{
front = rear = q;
}else{
rear.setNext(q);
rear = q;
}
size++;
return true;
}
// 出隊列操作
public E out() {
if(size == 0)
return null;
E i = front.getData();
front = front.getNext();
size--;
return i;
}
// 取對頭元素
public E head() {
returnfront.getData();
}
// 求隊列的長度
public int size() {
returnsize;
}
// 判斷隊列是否為空
public boolean isEmpty() {
if(rear ==front)
return true;
return false;
}
//清空隊列
public void clear() {
front = rear = null;
size =0;
}
}
7、銀行叫號實現(排隊機)
public class TestBankQueue {
public static void main(String[] args){
int windowcount =2;//設置銀行櫃台的服務窗口數。先設為1,然后依次增加看效果
//創建服務窗口數組
ServiceWindow[] sw = new ServiceWindow[windowcount];
//創建排隊機對象
QueueMachine qm=new QueueMachine("0800","1630");
//啟動排隊機服務
qm.start();
for (int i = 0; i < windowcount; i++)
{
//初始化服務窗口數組
sw[i] = new ServiceWindow(qm.getQueue());
//將名字設置為服務窗口的編號
sw[i].setName( "" + (i + 1));
//啟動窗口服務
sw[i].start();
}
}
}
8、銀行叫號實現(測試主類)
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Scanner;
public class QueueMachine extends Thread {
private int number;//排隊機當前最新號碼
private IQueue<Integer> queue;//排隊機維持的隊列
private String starttime;//排隊機工作開始時間,例如:0800為早上8點
private String endtime;//排隊機工作結束進間例如:1630為下午4點半
public QueueMachine( String starttime,String endtime){
queue=new SeqQueue<Integer>(Integer.class,100);
//queue=new LinkQueue<Integer>();
this.starttime=starttime;
this.endtime=endtime;
}
//獲取服務隊列
public IQueue<Integer> getQueue() {
return queue;
}
//顧客按回車獲取服務號,將服務號入隊、打印服務小票
public void run(){
Scanner sc=new Scanner(System.in);
SimpleDateFormat df = new SimpleDateFormat("HHmm");//設置日期格式
//獲取當前系統時間並轉換為設置的日期格式
String time=df.format(new Date());
while (time.compareTo(starttime)>=0 && time.compareTo(endtime)<=0)
{
System.out.println("按回車鍵獲取號碼:");
sc.nextLine();
int callnumber=++number;
if (queue.in(callnumber))
{
System.out.println(String.format("您的號碼是:%d,你前面有%d位,請等待!", callnumber, queue.size()-1));
time=df.format(new Date());
}
else{
System.out.println("現在業務繁忙,請稍后再試!"); //隊列滿時出現這種情況
number--;
}
}
sc.close();
System.out.println("己到下班時間,請明天再來");
}
}
9、銀行叫號實現(服務窗口)
public class ServiceWindow extends Thread {
private IQueue<Integer>queue;//服務隊列
//在構造函數中指定服務的隊列
public ServiceWindow(IQueue<Integer>queue) {
this.queue =queue;
}
//窗口叫號及銀行櫃台人員工作時間10000ms
public void run() {
while (true) {
synchronized (queue) {
if (queue.size()>0) {
System.out.println(String.format("請%d號到%s號窗口!",
queue.out(), Thread.currentThread().getName()));
}
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}
}
