• [Daily]猫狗队列——”子类管理器“


    【题目】

    • 有猫狗类如下:
    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++));
    			else
    				cout<<"添加的元素类型有误,请检查!"<<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;     //赋值成功
    
  • 相关阅读:
    [转]GO语言下载、安装、配置
    Go语言标准库
    GPIO与外部中断
    i.MX RT1050 Boot(RT1021通用)
    i.MX RT系列跨界处理器电源时序设计要点
    i.MX RT1050 Memory Management
    Java如何实现定时任务?
    Java如何使用实时流式计算处理?
    音色的秘密:泛音
    用程序计算出钢琴88个键的音高
  • 原文地址:https://www.cnblogs.com/ZhuSenlin/p/12388326.html
Copyright © 2020-2023  润新知