数据结构(Java)——队列的实例
参考Java软件结构与数据结构 John Lewis Joseph chase 著 金名译
乱世英雄起四方,有枪就是草头王 ——易中天《百家讲坛》
1.JavaAPI中的队列
public interface Queueextends Collection
A collection designed for holding elements prior to processing. Besides basic Collection operations, queues provide additional insertion, extraction, and inspection operations. Each of these methods exists in two forms: one throws an exception if the operation fails, the other returns a special value (either null or false, depending on the operation). The latter form of the insert operation is designed specifically for use with capacity-restricted Queue implementations; in most implementations, insert operations cannot fail.
Operator | Throws exception | Returns special value |
---|---|---|
Insert | add(e) | offer(e) |
Remove | remove() | poll() |
Examine | element() | peek() |
2.代码密钥
package ds.java.ch05;
import java.util.LinkedList;
import java.util.Queue;
/**
* @author LbZhang
* @version 创建时间:2015年11月17日 上午9:08:19
* @description 使用重复密钥来编码、解码消息 那些整数密钥值存储在一个队列中,使用一个密钥值之后,该值会被重新送回到队尾,
* 这样较长的消息可以按需继续重复使用该密钥。 注意:队列是一种可存储 重复编码密钥的便利 集合
*
* 解析:这个程序实际使用到了两份密钥,它们分别存储在两个单独的队列中。 思路:消息编码这使用一份密钥,消息解码者使用另一份密钥。
*
*/
public class Codes {
public static void main(String[] args) {
int[] key = { 5, 12, -3, 8, -9, 4, 10 };
Integer keyValue;
String encode = "";
String decode = "";
String message = "All programmers are playwrights and all "
+ "computers are lousy actors.";
Queue<Integer> encodingQueue = new LinkedList<Integer>();
Queue<Integer> decodingQueue = new LinkedList<Integer>();
/**
* 初始化密钥队列
*/
for(int i = 0;i<key.length;i++){
encodingQueue.add(key[i]);
decodingQueue.add(key[i]);
}
/**
*encode message
*/
for(int i=0;i<message.length();i++){
keyValue = encodingQueue.remove();
encode += (char) ((int)message.charAt(i) + keyValue.intValue());
encodingQueue.add(keyValue);
}
System.out.println("Encode Message :\n"+encode);
/**
*decode message
*/
for(int i=0;i<encode.length();i++){
keyValue = decodingQueue.remove();
decode += (char) ((int)encode.charAt(i) - keyValue.intValue());
decodingQueue.add(keyValue);
}
System.out.println("Encode Message :\n"+decode);
/**
* 改程序在字母表结尾并没有环绕,他能够对unicode字符集中的任何字符编码,会将该字符移动到U字符集的另一个位置 包括标点符号
*/
}
}
3.售票口模拟
案例假设:
- 只排一对,而且先到的人先得到服务(这是一个队列)。
- 平均每隔15秒就会来一位顾客。
- 如果有空闲的售票口,在顾客抵达之时就会马上处理,在顾客抵达之时就会马上处理。
- 从顾客来到售票口到处理完顾客请求、到顾客离开,这个过程平均需要2分钟(120秒)。
3.1 Customer.java
package ds.java.ch05;
/**
* @author LbZhang
* @version 创建时间:2015年11月17日 上午10:11:02
* @description
* Customer对象负责跟踪顾客抵达售票口的时间和顾客买票后离开售票口的时间.
* 于是,顾客买票所花的总时间 就是抵达时间与离开时间之差。
* 辅助类
*/
public class Customer {
private int arrivalTime;
private int departureTime;
public Customer(int arrives) {
this.arrivalTime = arrives;
this.departureTime = 0;
}
public int getArrivalTime() {
return arrivalTime;
}
public void setArrivalTime(int arrivalTime) {
this.arrivalTime = arrivalTime;
}
public int getDepartureTime() {
return departureTime;
}
public void setDepartureTime(int departureTime) {
this.departureTime = departureTime;
}
public int totalTime(){
return departureTime-arrivalTime;
}
}
3.2 TicketCounter.java
package ds.java.ch05;
import java.util.LinkedList;
import java.util.Queue;
/**
* @author LbZhang
* @version 创建时间:2015年11月17日 上午10:27:12
* @description 模拟将创建一个顾客队列,接着观察如果仅有一个售票口,处理这些的购票需要多长时间,
* 然后在考虑两个售票口时,需要多少时间,接着再考虑三个售票口。继续这一过程直到达
* 到10个售票口最后我们比较每个顾客所需的平均处理时间。
* 由于假定每个15秒会来一个顾客(平均情况),于是可以预先载入一个顾客队列,在这个 模拟中将处理100位顾客
*/
public class TicketCounter {
final static int PROCESS = 120;// /处理时间
final static int MAX_CASHIERS = 10;//最大收银人数
final static int NUM_CUSTOMERS = 100;
public static void main(String[] args) {
Customer customer;
Queue<Customer> customerQueue = new LinkedList<Customer>();
int[] cashierTime = new int[MAX_CASHIERS];
//收银员的时间标记
int totalTime, averageTime, departs;
/** process the simulation for various number of cashiers */
for (int cashiers = 0; cashiers < MAX_CASHIERS; cashiers++) {
/** set each cashiers time to zero initially */
for (int count = 0; count < cashiers; count++)
cashierTime[count] = 0;
/** load customer queue */
for (int count = 1; count <= NUM_CUSTOMERS; count++)
customerQueue.offer(new Customer(count * 15));
totalTime = 0;//使用的总体时间
/** process all customers in the queue */
while (!(customerQueue.isEmpty())) {
//不同数量的收银员在进行售票的时候处理顾客服务的时间需求
for (int count = 0; count <= cashiers; count++) {
if (!(customerQueue.isEmpty())) {
customer = customerQueue.poll();
if (customer.getArrivalTime() > cashierTime[count])
departs = customer.getArrivalTime() + PROCESS;
else
departs = cashierTime[count] + PROCESS;
// 离开时间的设置
customer.setDepartureTime(departs);
cashierTime[count] = departs;
//每个顾客使用的最总时间
totalTime += customer.totalTime();
}
}
}
/** output results for this simulation */
averageTime = totalTime / NUM_CUSTOMERS;
System.out.println("Number of cashiers: " + (cashiers + 1));
System.out.println("Average time: " + averageTime + "\n");
}
}
}
4.队列的相关理解
-链表实现中head可能和tail引用相等:当队列为空或者队列中只有一个元素时会出现这种情况。
-环形数组实现中,front和rear可能相等:队列为空或者队列已满。
-dequeue操作复杂度为O(n)的非环形数组实现的时间复杂度最差。
-比较链式和数组实现:两种数组实现都会因为数组中为填充元素而浪费空间。链表中每个存储元素都会占用更多的存储空间。