public class Pet {
private String type;
public Pet(String type){
this.type=type;
}
public String getPetType(){
return this.type;
}
}
public class Dog extends Pet{
public Dog(){
super("dog");
}
}
public class Cat extends Pet{
public Cat(){
super("cat");
}
}
宠物、狗和猫类如上:
实现一种猫狗队列的结构,要求如下:
- 用户可以调用add方法将cat或dog类的实例放入队列中;
- 用户可以调用pollAll方法,将队列中所有的实例按照队列的先后顺序依次弹出;
- 用户可以调用pollDog方法,将队列中的dog类的实例按照队列的先后顺序依次弹出;
- 用户可以调用pollCat方法,将队列中cat类的实例按照进队列的先后顺序依次弹出;
- 用户可以调用isEmpty方法,检查队列中是否还有dog或者cat实例;
- 用户可以调用isDogEmpty方法,检查队列中是否还有dog类的实例;
- 用户可以调用isCatEmpty方法,检查队列中是否还有cat类的实例;
解答:
本题考察实现特殊数据结构能力,以及针对特殊功能的算法设计能力。
- cat队列只放cat实例,dog队列只放dog实例,再用一个总队列放所有的实例。错误原因:cat、dog以及总队列的更新问题。
- 用哈希表,key表示一个cat实例或dog实例,value表示这个实例进队列的次序。错误原因:不能支持一个实例多次进队列的功能需求,因为哈希表的key只能对应一个value值。
- 将用户原有的cat或dog类改写,加一个计数项来表示某一个实例进队列的时间。错误原因:不能擅自改变用户的类结构。
本题实现将不同的实例盖上时间戳的方法,但是又不能改变用户本身的类,所以定义一个新的类,具体实现请参看如下:
public class PetEnterQueue{
private Pet pet;
private Long number;
public PetEnterQueue(Pet pet,long count){
this.pet=pet;
this.number=number;
}
public Pet getPet() {
return pet;
}
public Long getNumber() {
return number;
}
public String getEnterPetType(){
return this.pet.getPetType();
}
}
在构造PetEnterQueue类时,pet是用户原有的实例,count就是这个实例的时间戳。
我们实现的队列其实是PetEnterQueue类的实例。答题来说,首先有一个不断累加的数据项,用来表示实例进队列的时间;同时有两个队列,一个是只放dog类的实例队列dogQ,另一个是只放cat类的实例队列catQ。
在加入实例时,如果实例是dog,就盖上时间戳,生产对应的PetEnterQueue类的实例,然后放入dogQ;反之如果是cat类的实例,也是如此。具体过程请看如下DogCatQueue类的add方法。
只想弹出dog类的实例时,从dogQ里不断弹出即可,具体过程参看如下的DogCatQueue类的pollDog方法。
反之只想弹出cat类的实例时,从catQ里不断弹出即可,具体过程请看如下DogCatQueue类的pollCat方法。
想按实际顺序弹出实例时,因为dogQ的队列头表示所有dog实例中的最早进入队列的实例,同时catQ的队列头表示cat实例找那个最早进队列的实例。则比较这两个队列头的时间戳,谁更早就弹出谁,具体请参看pollAll方法。
具体代码如下:
public class DogAndCatQueue {
private Queue<PetEnterQueue> dogQ;
private Queue<PetEnterQueue>catQ;
private long count;
public DogAndCatQueue(){
this.catQ=new LinkedList<>();
this.dogQ=new LinkedList<>();
this.count=0;
}
public void add(Pet pet){
if (pet.getPetType().equals("dog")){
this.dogQ.add(new PetEnterQueue(pet,this.count++));
}else if (pet.getPetType().equals("cat")){
this.catQ.add(new PetEnterQueue(pet,this.count++));
}else {
throw new RuntimeException("err,not dog or cat");
}
}
public Pet pollAll(){
if (!this.dogQ.isEmpty()&&!this.catQ.isEmpty()){
if (this.dogQ.peek().getNumber()<this.catQ.peek().getNumber()){
return this.dogQ.poll().getPet();
}else {
return this.catQ.poll().getPet();
}
}else if (!this.dogQ.isEmpty()){
return this.dogQ.poll().getPet();
}else if (!this.catQ.isEmpty()){
return this.catQ.poll().getPet();
}else {
throw new RuntimeException("err,queue is empty!");
}
}
public Dog pollDog(){
if (!this.dogQ.isEmpty()){
return (Dog)this.dogQ.poll().getPet();
}else {
throw new RuntimeException("Dog queue is empty!");
}
}
public Cat pollCat(){
if (!this.catQ.isEmpty()){
return (Cat)this.catQ.poll().getPet();
}else {
throw new RuntimeException("Cat queue is empty!");
}
}
public boolean isEmpty(){
return this.catQ.isEmpty()&&this.dogQ.isEmpty();
}
public boolean isDogQueueEmpty(){
return this.dogQ.isEmpty();
}
public boolean isCatQueueEmpty(){
return this.catQ.isEmpty();
}
public static void main(String[] args) {
DogAndCatQueue dogAndCatQueue = new DogAndCatQueue();
Pet cat = new Pet("cat");
Pet cat02 = new Pet("cat");
Pet dog = new Pet("dog");
Pet dog02 = new Pet("dog");
Pet dog03 = new Pet("dog");
dogAndCatQueue.add(cat);
dogAndCatQueue.add(cat);
dogAndCatQueue.add(cat02);
dogAndCatQueue.add(dog);
dogAndCatQueue.add(dog02);
dogAndCatQueue.add(dog03);
}
}
断点验证:
我们看到对应猫狗实例都是有编号的,说明有序,既然有序pollAll方法就实现了。