第一章 栈和队列
1.4 猫狗队列
【题目】
宠物、猫和狗的类定义如下:
public class Pet {
private String type;
public Pet(String type) {
this.type = type;
}
public String getPetType() {
return this.type;
}
}
public class Cat extends Pet {
public Cat() {
super("cat");
}
}
public class Dog extends Pet {
public Dog() {
super("dog");
}
}
实现一种猫狗队列的结构,要求如下:
- 可以调用 add 方法将 Cat 类或 Dog 类的实例加入队列中;
- 可以调用 pollAll 方法,将队列中的所有实例按照进队列的先后顺序依次弹出;
- 可以调用 pollCat 方法,将队列中 Cat 类的实例按照进队列的先后顺序依次弹出;
- 可以调用 pollDog 方法,将队列中 Dog 类的实例按照进队列的先后顺序依次弹出;
- 可以调用 isEmpty 方法,检查队列中是否还有 Cat 或 Dog 的实例;
- 可以调用 isCatEmpty 方法,检查队列中是否还有 Cat 的实例;
- 可以调用 isDogEmpty 方法,检查队列中是否还有 Dog 的实例;
【难度】
士 ★☆☆☆
【题解】
本题考查实现特殊数据结构的能力以及针对特殊功能的算法设计能力。
本题实现将不同的实例加上时间戳的方法,但是不改变原来的类结构,所以定义一个新的类 PetWithOrder。PetWithOrder类在构造时,pet 是原有的实例,count 作为这个实例的时间戳。实现的队列其实是 PetWithOrder 类的实例。首先需要有一个不断累加的数据项,用来表示实例进入队列的顺序。同时维护两个队列,一个是只放 Cat 类实例的队列 catQ,另一个是只放 Dog 类实例的队列 dogQ。在加入任意实例时,对应生成包含唯一时间戳标识的 PetWithOrder 类的实例,然后加入 catQ 或 dogQ 中。仅弹出 Cat 类或者 Dog 类之一的实例时,只需从对应队列中不断弹出即可。若按实际顺序弹出任意实例时,则需要比较两个队列头的实例的时间戳,弹出其中较小者。
【实现】
- Pet.java
public class Pet {
private String type;
public Pet(String type) {
this.type = type;
}
public String getPetType() {
return this.type;
}
}
- Cat.java
public class Cat extends Pet {
public Cat() {
super("cat");
}
}
- Dog.java
public class Dog extends Pet {
public Dog() {
super("dog");
}
}
- PetWithOrder.java
public class PetWithOrder {
private Pet pet;
private int order;
public PetWithOrder(Pet pet, int order) {
this.pet = pet;
this.order = order;
}
public Pet getPet() {
return pet;
}
public int getOrder() {
return order;
}
public String getPetType() {
return this.pet.getPetType();
}
}
- CatAndDogQueue.java
import java.util.LinkedList;
import java.util.Queue;
public class CatAndDogQueue {
private Queue<PetWithOrder> catQ;
private Queue<PetWithOrder> dogQ;
private int count;
public CatAndDogQueue() {
catQ = new LinkedList<>();
dogQ = new LinkedList<>();
count = 0;
}
public void add(Pet pet) throws Exception {
if (pet instanceof Cat) {
PetWithOrder pwo = new PetWithOrder(pet, count++);
catQ.add(pwo);
} else if (pet instanceof Dog) {
PetWithOrder pwo = new PetWithOrder(pet, count++);
dogQ.add(pwo);
} else {
throw new RuntimeException("Not Cat or Dog!");
}
}
public Pet pollAll() throws Exception {
if (!this.catQ.isEmpty() && !this.dogQ.isEmpty()) {
if (this.catQ.peek().getOrder() < this.dogQ.peek().getOrder()) {
return this.catQ.poll().getPet();
} else {
return this.dogQ.poll().getPet();
}
} else if (!this.catQ.isEmpty()) {
return this.catQ.poll().getPet();
} else if (!this.dogQ.isEmpty()) {
return this.dogQ.poll().getPet();
} else {
throw new RuntimeException("栈为空!");
}
}
public Pet pollCat() throws Exception {
if (!this.catQ.isEmpty()) {
return this.catQ.poll().getPet();
} else {
throw new RuntimeException("栈为空!");
}
}
public Pet pollDog() throws Exception {
if (!this.dogQ.isEmpty()) {
return this.dogQ.poll().getPet();
} else {
throw new RuntimeException("栈为空!");
}
}
public boolean isEmpty() {
return this.catQ.isEmpty() && this.dogQ.isEmpty();
}
public boolean isCatEmpty() {
return this.catQ.isEmpty();
}
public boolean isDogEmpty() {
return this.dogQ.isEmpty();
}
}
- CatAndDogQueueTest.java
public class CatAndDogQueueTest {
public static void main(String[] args) throws Exception {
CatAndDogQueue queue = new CatAndDogQueue();
for (int i = 0; i < 5; i++) {
Cat cat = new Cat();
Dog dog = new Dog();
queue.add(cat);
queue.add(dog);
}
queue.pollCat();
queue.pollDog();
queue.pollAll();
queue.pollAll();
}
}