前言
本文是【程序员代码面试指南(第二版)学习笔记】C#版算法实现系列之一,用C#实现了《程序员代码面试指南》(第二版)栈和队列中的猫狗队列。
一、题目要求
宠物、猫、狗类的定义如下:
public class Pet {
private string type;
public Pet(string type) {
this.type = type;
}
public string GetPetType() {
return type;
}
}
public class Dog: Pet {
public Dog(): base("dog") {}
}
public class Cat: Pet {
public Cat(): base("cat") {}
}
要求实现以下功能:
1、用户可以调用 Add 方法将 Cat 类或 Dog 类的实例放入队列中;
2、用户可以调用 PollAll 方法,将队列中所有的实例按照进队列的先后顺序依次弹出;
3、用户可以调用 PollDog 方法,将队列中 Dog 类的实例按照进队列的先后顺序依次弹出;
4、用户可以调用 PollCat 方法,将队列中 Cat 类的实例按照进队列的先后顺序依次弹出;
5、用户可以调用 IsEmpty 方法,检查队列中是否还有 Dog 或 Cat 的实例;
6、用户可以调用 IsDogEmpty 方法,检查队列中是否有 Dog 类的实例;
7、用户可以调用 IsCatEmpty 方法,检查队列中是否有 Cat 类的实例。
注:不可修改原有的宠物和猫狗类,且可能同一个实例入队多次
二、算法设计及代码实现
2.1 算法思想
概述:由于不可以修改题目给出的类,那么就需要另写一个类,在该宠物类中添加上加入队伍的时间计数器,其中计数器越小表示入队越早。入队时,需要每入队一个猫或狗就让计数器加一;出队时,单独的猫狗队列出队不需要特殊操作,整个队列出队就需要判断猫狗队首的计数器,弹出最小的。判空就看长度判断即可。
自定义宠物类:有宠物和计数器两个字段,提供读取这两个字段的方法/属性,提供初始化两个字段的构造函数以及获取该宠物的类型的方法。
猫狗队列类:猫狗队列分开初始化,并初始化一个初始值为0的计数器。
1、入队:判断入队元素类型,类型必须是猫狗,是其他则抛出异常(在入队时控制好类型,其他方法内就不用判断是否存在猫狗以外的类型了)。猫则入猫队,狗则入狗队。
2、狗队出队:弹出一个狗队元素。
3、猫队出队:弹出一个猫队元素。
4、总队出队:由于猫狗队列可能有一个为空,所以要先判断不为空,才可以比较两队首的计数器。如果一队为空,那么直接弹出另一队的元素;都不为空,弹出两队中计数器较小的元素。
5、判断狗队为空:狗队长度为0返回true,否则为false。
6、判断猫队为空:猫队长度为0返回true,否则为false。
7、判断总队为空:狗队为空且猫队为空返回true,否则为false。
2.2 代码实现
using System.Collections;
public class PetEnterQueue {
private Pet pet;
private long count;
public Pet PetProperty {
get => pet;
}
public long Count {
get => count;
}
public PetEnterQueue(Pet pet, long count) {
this.pet = pet;
this.count = count;
}
public string GetPetType() {
return pet.Type;
}
}
public class CatDogQueue {
private Queue<PetEnterQueue> dogQue = new();
private Queue<PetEnterQueue> catQue = new();
private long count = 0;
// 入队
public void Add(Pet pet) {
if (pet.Type == "dog") {
dogQue.Enqueue(new PetEnterQueue(pet, count++));
}
else if(pet.Type == "cat") {
catQue.Enqueue(new PetEnterQueue(pet, count++));
}
else {
throw new SystemException("入队类型应该为猫或狗!");
}
}
// 狗队列出队
public Dog? PollDog() {
return dogQue.Dequeue().PetProperty as Dog;
}
// 猫队列出队
public Cat? PollCat() {
return catQue.Dequeue().PetProperty as Cat;
}
// 从猫狗总队列中弹出一个应该出队的
public Pet? PollAll() {
// 其中一队为空
if (IsDogEmpty()) {
return PollCat();
}
if (IsCatEmpty()) {
return PollDog();
}
// 都不为空
if (dogQue.Peek().Count < catQue.Peek().Count) {
return PollDog();
}
else {
return PollCat();
}
}
// 判断狗队列是否为空
public bool IsDogEmpty() {
return dogQue.Count == 0? true: false;
}
// 判断猫队列是否为空
public bool IsCatEmpty() {
return catQue.Count == 0? true: false;
}
// 判断猫狗总队列是否为空
public bool IsEmpty() {
return IsDogEmpty() && IsCatEmpty();
}
}