【题目】
- 有猫狗类如下:
class Pet
{private:string m_type;public:Pet(string _type){ m_type=_type; }string GetPetType(){ return m_type; }
};class Dog : public Pet
{public:Dog() : Pet("dog"){}
};class Cat : public Pet
{public:Cat() : Pet("cat"){}
};
- 要求实现如下功能:
- add:方法将cat类或dog类的实例放入队列
- pollAll : 将队列出队(按照队列的先后顺序)
- pollDog:将队列的dog类实例按照队列的先后顺序出队
- pollCat:同理
- isEmpty:队列是否为空
- isDogEmpty:检查队列是否存在dog类实例
- isCatEmpty:同理
【分析】
- 猫和狗两个类皆为Pet类的子类。很显然,最适合的方法就是利用两个队列来组合在同一个类里面。那么问题来了,如何在两个队列中确定总的入队顺序呢?
- 确定总入队顺序主要是为了满足 pollAll 方法的实现。
- 在书中明确指出了最好不要改变原本的猫狗类,因此我们可以将这两个类做一层包装。而数据类型用Pet来表示Cat 和 Dog,Pet作为统一的数据类型。
- 设计一个Tag时间戳来记录入队顺序即可
这里有一个问题:既然已经猫和狗既然被封装成同一个类型,为什么不直接用一个队列存储即可?
因为我们还要考虑到上述7种操作种,4种分别对类进行操作,如果只用以一个队列进行存储,复杂度将会大大提高。
这是很显然的,具体问题具体分析,本题考察的就是特殊数据结构的设计
【实现】
- 实现语言:C++
- 源代码
/*猫狗队列*/#include<iostream>
#include<string>
#include<queue>
using namespace std;class Pet
{private:string m_type;public:Pet(){}Pet(string _type){ m_type=_type; }string GetPetType(){ return m_type; }
};class Dog : public Pet
{public:Dog() : Pet("dog"){}
};class Cat : public Pet
{public:Cat() : Pet("cat"){}
};//将两个同父类的子类(Cat And Dog)包装起来
//方便用同种泛型的Queue包装起来
class PetEnterQueue
{private:Pet m_pet;long m_count; //这个类的最终目的:就是包装一个时间戳,以确定入队的顺序 public:PetEnterQueue(Pet _pet,long _count){m_pet=_pet;m_count=_count;}Pet getPet() { return m_pet;}long getCount(){ return m_count;}string getType(){ return m_pet.GetPetType();}
}; //猫狗队列类
class CatAndDogQueue
{private:queue<PetEnterQueue> m_catQueue; //猫队列 queue<PetEnterQueue> m_dogQueue; //狗队列 long m_Count; //队列元素的个数public:CatAndDogQueue(){ m_Count=0; } //构造函数中将容量设为0//主要操作函数//add:方法将cat类或dog类的实例放入队列void add(Pet pet){if(pet.GetPetType()=="dog") //狗元素m_dogQueue.push(PetEnterQueue(pet,m_Count++)); else if(pet.GetPetType()=="cat")m_catQueue.push(PetEnterQueue(pet,m_Count++));elsecout<<"添加的元素类型有误,请检查!"<<endl;} //pollAll : 将队列出队(按照队列的先后顺序)Pet pollAll(){Pet pet;if(!m_catQueue.empty()&&!m_dogQueue.empty()) //两个队列皆不为空时 {if(m_catQueue.front().getCount() > m_dogQueue.front().getCount()){pet=m_dogQueue.front().getPet();m_dogQueue.pop();}else{pet=m_catQueue.front().getPet();m_catQueue.pop();}}else if(!m_dogQueue.empty()) {pet=m_dogQueue.front().getPet();m_dogQueue.pop();}else if(!m_catQueue.empty()){pet=m_catQueue.front().getPet();m_catQueue.pop();}else{cout<<"当前队列为空队,无法出队!"<<endl;return pet; }return pet; }//pollDog:将队列的dog类实例按照队列的先后顺序出队 Pet pollDog(){Pet pet;if(m_dogQueue.empty()){cout<<"狗队为空,无法出队"<<endl;return pet;}pet=m_dogQueue.front().getPet();m_dogQueue.pop();return pet;} //pollCat:同理Pet pollCat(){Pet pet;if(m_catQueue.empty()){cout<<"猫队为空,无法出队"<<endl;}pet=m_catQueue.front().getPet();m_catQueue.pop();return pet;}//isEmpty:队列是否为空bool isEmpty(){return m_dogQueue.empty()&&m_catQueue.empty(); } //isDogEmpty:检查队列是否存在dog类实例bool isDogEmpty(){return m_dogQueue.empty();}//isCatEmpty:同理bool isCatEmpty(){return m_catQueue.empty();} void ShowCount(){cout<<"dog count : "<<m_dogQueue.size()<<endl;cout<<"cat count : "<<m_catQueue.size()<<endl;//cout<<"合计 : "<< m_dogQueue.size()+m_catQueue.size()<<endl;}
};
【此外】
- “子类管理器”,顾名思义,它可以很好的管理同一个父类的不同子类的集合。这可以延申到其他数据结构中
- 在C++中,子类实例转化为父类实例(在我印象中,这是没有的,也是不提倡的)。而Java上可以强制类型转换。因此,在pollCat()等方法中也可以返回子类类型,上述C++我直接返回Pet(父类类型)
- 可以直接父类实例给子类实例进行赋值(在编写代码时没有想到这一点)
Pet pet;
Dog dog;
Pet *pPet=&dog;
*pPet=pet; //赋值成功