隊列的設計與實現及應用
一、目的和要求:
(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()); } } } }