貓狗佇列的再解
貓狗佇列是一個很經典的問題了吧,在書上我也翻看了很久;而網上的答案呢,也是千篇一律的,跟書的程式碼也是一字不差的,幾乎除了照搬似乎都沒什麼思路可言的,甚至連書上提到注意的點都沒有…
一開始我是沒什麼思路的,翻來覆去研究書上,發現原來挺簡單;但用思路寫起來還真不是一回事,挺難的。各個問題涉及到的地方很多,就是如何解決的問題很多,特別是題目的第二點要求。


以下是我研究書好一會做題的過程,也發現書上一些不太好的問題吧,比如對裝載 Pet 例項的類命名為:PetEnterQueue ,真的很容易造成誤解以為是個佇列;而且我覺得書中所寫的這類似乎有些多餘了,這並不是說他的實現方式不對,這樣的實現思路也的確是要這樣做的;但其實只要建立一個由貓和狗組合成的共同的類就好了,實現的方法寫在其中也OK,以下是我的解題過程。
題目:寵物、狗、貓類程式碼如下
package com.pat;
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()、pollCat(),將佇列中dog類、cat類的例項按照進佇列的先後順序依次彈出
- 使用者可以呼叫isEmpty(),檢查佇列中是否還有dog、cat的例項
- 使用者可以呼叫isDogEmpty()、isCatEmpty(),分別檢查佇列中是否還有dog、cat的例項
思路:
1) 使用者可以呼叫add() ,cat類或dog類的例項放入佇列中
add() 也需要裝載一個 Pet 的例項(多型),如何區分繼承Pet類的 cat 和 dog 物件
public Cat(){ super("cat"); }
由於Cat 和 Dog 的構造方法有 super("xxx")
這下可以用 equals 比較字串區分不同的 cat 和 dog 物件,然後將符合條件的物件加入進 Cat 或 Dog 的佇列中。
//最好避免魔法值,此中僅為示例 boolean bool = pet.getPetType().equal("cat"); if(bool){ add(pet); }
2) 使用者可以呼叫pollAll(),將佇列中所有例項按照佇列先後順序依次彈出
按照依次按順序彈出,根據類別的佇列中的物件總數或佇列的大小,來決定先那個佇列使用 poll() 將所有物件出列。比如 Cat 佇列的物件少於 Dog 佇列,就將 Cat 佇列先執行 poll() 。這裡將 Cat 佇列命名為 catQ,Dog 佇列則為 dogQ
if(catQ.size() < dogQ.size()){ this.catQ.poll(); }else{ this.dogQ.poll(); }
當然,在此之前還需要做一個非空的判斷
if (this.catQ.isEmpty() && this.dogQ.isEmpty()) { throw new RuntimeException("empty"); }
實現:
package com.pet.dc.queue;
import com.pet.Pet;
import java.util.LinkedList;
import java.util.Queue;
/**
* @author lorem
*/
public class CatDogQueue {
private Queue<Pet> catQ;
private Queue<Pet> dogQ;
String cat = “cat”;
String dog = “dog”;
public CatDogQueue() {
// linkedList 本質上和queue 是一樣的,先進先出
this.catQ = new LinkedList<Pet>();
this.dogQ = new LinkedList<Pet>();
}
public void add(Pet pet) {
if (pet.getPetType().equals(cat)) {
this.catQ.add(pet);
}else if(pet.getPetType().equals(dog)) {
this.dogQ.add(pet);
} else {
throw new RuntimeException(“err,not cat not dog”);
}
}
public void pollAll() {
if (this.catQ.isEmpty() && this.dogQ.isEmpty()) {
throw new RuntimeException(“empty”);
}
if (this.catQ.size() > this.dogQ.size()) {
this.dogQ.poll();
} else {
this.catQ.poll();
}
}
public void pollDog() {
if (!this.dogQ.isEmpty()) {
this.dogQ.poll();
} else {
throw new RuntimeException(“dog is empty”);
}
}
public void pollCat() {
if (!this.catQ.isEmpty()) {
this.catQ.poll();
} else {
throw new RuntimeException(“cat is empty”);
}
}
public boolean isEmpty() {
if (!this.dogQ.isEmpty() && !this.catQ.isEmpty()) {
return false;
}
return true;
}
public boolean isDogEmpty() {
return this.dogQ.isEmpty();
}
public boolean isCatEmpty() {
return this.catQ.isEmpty();
// if (this.catQ.isEmpty()){
// return true;
// }else{
// return false;
// }
}
}
測試:
測試的話,在 maven 模組配置好 Junit4 再到 test 測試資料夾寫好測試類,即可測驗了
import com.pet.Pet; import com.pet.dc.queue.CatDogQueue; import org.junit.Test;
public class JTest {
@Test
public void test() {
Pet cat1 = new Pet(“cat”);
Pet cat2 = new Pet(“cat”);
Pet dog1 = new Pet(“dog”);
CatDogQueue cdq = new CatDogQueue();
cdq.add(cat1);
cdq.add(cat2);
// assert cat1.getPetType().equals(“cat”);
System.out.println(cdq.isDogEmpty());
}
}
看了一個照搬書上還不錯的例子, ofollow,noindex">通過給定的類實現貓狗佇列 ,他的 offer() 挺好的,如果佇列已滿再插入直接返回 false,不像add() 丟擲異常中斷執行 。異常儘早暴露原則的話,哦,那真是看情況而定了。