唐老狮C#进阶课程练习题(自写,如果有更好的方法欢迎讨论)
目录
第4课 Stack 栈:
1.简述栈的存储规则:先进后出
2.写一个方法计算任意数的二进制,用栈结构方式储存,之后打印出来
private static void ToBinarySystem(int num)
{
Stack stack = new Stack();
for (;num >= 1;)
{
stack.Push(num % 2);
num = num / 2;
}
foreach (var item in stack)
{
Console.Write(item);
}
}
第6课 Queue 队列
1.简述队列的存储规则:先进先出
2.使用队列存储消息,一次性存10条消息,每隔一段时间打印一条消息,控制台打印消息时要有明显停顿感(暂时未实现停顿感)
static void PrintQueue()
{
Queue queue = new Queue();
for (int i = 0; i < 10; i++)
{
queue.Enqueue(i);
}
foreach (var item in queue)
{
Console.WriteLine(item);
}
}
下面这个是人工智能代写效果,可供参考:
using System;
using System.Collections.Generic;
using System.Threading;
public class MessageQueue
{
private Queue<string> queue;
private int maxCount;
private int printInterval;
public MessageQueue(int maxCount, int printInterval)
{
this.queue = new Queue<string>();
this.maxCount = maxCount;
this.printInterval = printInterval;
}
public void Enqueue(string message)
{
lock (queue)
{
queue.Enqueue(message);
if (queue.Count == maxCount)
{
PrintMessages();
}
}
}
private void PrintMessages()
{
Console.WriteLine("Printing messages...");
while (queue.Count > 0)
{
Thread.Sleep(printInterval);
Console.WriteLine(queue.Dequeue());
}
}
}
public class Program
{
public static void Main()
{
MessageQueue messageQueue = new MessageQueue(10, 1000);
for (int i = 0; i < 10; i++)
{
messageQueue.Enqueue($"Message {
i + 1}");
}
}
}
第8课 Hashtable表
1.请描述Hashtable的存储规则:通过键值对进行存储
2.制作一个怪物管理器,提供创建怪物,移除怪物的方法。每个怪物都有自己的唯一ID
怪物管理器类:
/// <summary>
/// 怪物管理器,提供创建怪物,移除怪物的方法。每个怪物都有自己的唯一ID
/// </summary>
class MonsterManager
{
//创建怪物的哈希表
Hashtable monsterHashtable = new Hashtable();
/// <summary>
/// 创建怪物
/// </summary>
/// <param name="id">怪物的ID</param>
/// <param name="name">怪物的名字</param>
public void CreateMonster(int id,string name)
{
//判断现有的怪物哈希表里面存不存在要加入的怪物
if (!monsterHashtable.Contains(id))
{
//不存在,在哈希表里面加入怪物
monsterHashtable.Add(id, name);
}
else
{
//存在,给用户一个输出提示
Console.WriteLine("已存在此怪物ID");
}
}
/// <summary>
/// 通过ID移除怪物
/// </summary>
/// <param name="id">怪物ID</param>
public void RemoveMonster(int id)
{
//判断存不存在要删除的怪物
if (monsterHashtable.Contains(id))
{
//存在,删除怪物
monsterHashtable.Remove(id);
}
else
{
Console.WriteLine("不存在此怪物");
}
}
/// <summary>
/// 便利当前哈希表中的所有怪物
/// </summary>
public void ShowMonster()
{
foreach (var item in monsterHashtable.Keys)
{
Console.WriteLine("怪物ID:"+item+"\t 怪物名字:"+monsterHashtable[item]);
}
}
}
主函数调用:
static void Main(string[] args)
{
MonsterManager monsterMgr = new MonsterManager();
monsterMgr.CreateMonster(1, "1号怪物");
monsterMgr.CreateMonster(2, "2号怪物");
monsterMgr.CreateMonster(3, "3号怪物");
monsterMgr.ShowMonster();
Console.WriteLine("********进行删除操作**********");
monsterMgr.RemoveMonster(2);
monsterMgr.ShowMonster();
Console.ReadKey();
}
运行结果
怪物ID:3 怪物名字:3号怪物
怪物ID:2 怪物名字:2号怪物
怪物ID:1 怪物名字:1号怪物
********进行删除操作**********
怪物ID:3 怪物名字:3号怪物
怪物ID:1 怪物名字:1号怪物
第10课 泛型知识点
1.定义一个泛型方法,判断类型
定义一个泛型方法,方法内判断该类型为何类型,并返回类型的名称与占有的字节数,如果是int,则返回“整形,4字节”
只考虑以下类型
int:整形
char:字符
float:单精度浮点数
string:字符串
如果是其它类型,则返回“其它类型”
(可以通过typeof(类型) == typeof(类型)的方式进行类型判断)
private static string JudgmentType<T>()
{
if (typeof(T) == typeof(int))
{
return "整形" + "\t" + sizeof(int)+"字节";
}
else if(typeof(T) == typeof(char))
{
return "字符" + "\t" + sizeof(char) + "字节";
}
else if (typeof(T) == typeof(float))
{
return "单精度浮点数" + "\t" + sizeof(float) + "字节";
}
else if (typeof(T) == typeof(string))
{
return "字符串" + "\t" + "没有预定字节";
}
else
{
return "其他类型";
}
}
第12课 泛型约束
1.用泛型实现一个单例模式基类
这里提供的代码是在unity中使用的单例模式基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 定义一个基类,用于实现单例模式
public abstract class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
// 加锁的对象,用于线程安全
private static readonly object _lock = new object();
// 静态变量,用于存储单例实例
private static T _instance = null;
// 静态属性,用于获取单例实例
public static T Instance
{
get {
// 加锁,保证在多线程环境中只有一个实例被创建
lock (_lock) {
if (_instance == null)
_instance = FindObjectOfType<T>(); // 查找场景中是否已经存在该类型的对象
return _instance;
}
}
}
// 在 Awake() 中进行初始化,并处理多实例的情况
protected virtual void Awake()
{
// 加锁,保证在多线程环境中只有一个实例被创建
lock (_lock) {
// 第一次创建实例时,将自己设置为单例实例,不销毁该对象
if (_instance == null) {
_instance = (T)this;
DontDestroyOnLoad(gameObject); // 如果需要跨场景使用单例,使用 DontDestroyOnLoad 保持对象不被销毁
}
// 如果不同的实例被创建,销毁新的实例,保证单例的唯一性
else if (_instance != this) {
Destroy(gameObject);
}
}
}
// 如果该实例被销毁,将实例设置为空
protected virtual void OnDestroy()
{
if (_instance == this) {
_instance = null;
}
}
}
2.利用泛型知识点,仿造ArrayList实现一个不确定数组类型的类实现增删查改方法
class ArrayList<T>
{
private T[] items;
public ArrayList()
{
items = new T[0];
}
/// <summary>
/// 添加
/// </summary>
/// <param name="value"></param>
public void Add(T value)
{
T[] newItems = new T[items.Length + 1];
for (int i = 0; i < items.Length; i++)
{
newItems[i] = items[i];
}
newItems[newItems.Length - 1] = value;
items = newItems;
}
/// <summary>
/// 删除
/// </summary>
/// <param name="index"></param>
public void RemoveAt(int index)
{
if (index < 0 || index >= items.Length)
{
throw new IndexOutOfRangeException();
}
T[] newItems = new T[items.Length - 1];
for (int i = 0, j = 0; i < items.Length; i++)
{
if (i != index)
{
newItems[j] = items[i];
j++;
}
}
items = newItems;
}
/// <summary>
/// 查询
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T Get(int index)
{
if (index < 0 || index >= items.Length)
{
throw new IndexOutOfRangeException();
}
return items[index];
}
/// <summary>
/// 修改
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
public void Set(int index, T value)
{
if (index < 0 || index >= items.Length)
{
throw new IndexOutOfRangeException();
}
items[index] = value;
}
public int Count()
{
return items.Length;
}
}
主函数调用:
static void Main(string[] args)
{
ArrayList<int> intArray = new ArrayList<int>();
intArray.Add(1);
intArray.Add(2);
intArray.Add(3);
intArray.RemoveAt(1);
intArray.Set(1, 4);
Console.WriteLine(intArray.Get(0)); // 输出 1
Console.WriteLine(intArray.Get(1)); // 输出 4
Console.WriteLine(intArray.Count()); // 输出 2
ArrayList<string> stringArray = new ArrayList<string>();
stringArray.Add("apple");
stringArray.Add("banana");
stringArray.Add("orange");
stringArray.RemoveAt(2);
stringArray.Set(0, "pear");
Console.WriteLine(stringArray.Get(0)); // 输出 pear
Console.WriteLine(stringArray.Get(1)); // 输出 banana
Console.WriteLine(stringArray.Count()); // 输出 2
Console.ReadKey();
}
第14课 List 知识点
1.请描述List和ArrayList的区别
1.List支持泛型,ArrayList不支持泛型
2.List没有装箱与拆箱的操作,而ArrayList有装箱和拆箱操作,
2.建立一个整形List,为它添加10~1删除List中第五个元素遍历剩余元素并打印
List<int> list = new List<int>();
for (int i = 10; i > 0; i--)
{
list.Add(i);
}
list.RemoveAt(4);
foreach (var item in list)
{
Console.Write(item+"\t");
}
3.一个Monster基类,Boss和Gablin类继承它。在怪物类的构造函数中,将其存储到一个怪物List中遍历列表可以让Boss和Gablin对象产生不同攻击
class Monster
{
public static List<Monster> monsters = new List<Monster>();
public Monster()
{
monsters.Add(this);
}
public virtual void Attack()
{
Console.WriteLine("MonsterAtt");
}
}
class Boss : Monster
{
public override void Attack()
{
Console.WriteLine("BossAtt");
}
}
class Goblin : Monster
{
public override void Attack()
{
Console.WriteLine("GoblinAtt");
}
}
主函数调用:
Boss boss = new Boss();
Goblin goblin = new Goblin();
foreach (var item in Monster.monsters)
{
item.Attack();
}
第16课 Dictionary 知识点
1.使用字典存储0~9的数字对应的大写文字提示用户输入一个不超过三位的数,提供一个方法,返回数的大写 例如:306,返回叁零陆
Console.WriteLine("请输入一个不超过3位的数");
Console.WriteLine(GetInfo(int.Parse(Console.ReadLine())));
string GetInfo(int num)
{
Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(0, "零");
dic.Add(1, "壹");
dic.Add(2, "贰");
dic.Add(3, "叁");
dic.Add(4, "肆");
dic.Add(5, "伍");
dic.Add(6, "陆");
dic.Add(7, "柒");
dic.Add(8, "捌");
dic.Add(9, "玖");
string str = "";
//得百位
int b = num / 100;
if (b != 0)
{
str += dic[b];
}
//得十位数
int s = num % 100 / 10;
if (s != 0 || str != "")
{
str += dic[s];
}
//得个位
int g = num % 10;
str += dic[g];
return str;
}
2.计算每个字母出现的次数“Welcome to Unity World!”,使用字典存储,最后遍历整个字典,不区分大小写
string str = "Welcome to Unity World!";
Dictionary<char, int> strDic = new Dictionary<char, int>();
for (int i = 0; i < str.Length; i++)
{
if (strDic.ContainsKey(str[i]))
{
strDic[str[i]]+=1;
}
else
{
strDic.Add(str[i], 1);
}
}
foreach (var item in strDic.Keys)
{
Console.WriteLine("字母{0}出现了{1}次",item,strDic[item]);
}
第18课 顺序存储和链式存储 知识点
1.请说出常用的数据结构有哪些
数组、栈、队列、链表、树、图、堆、散列表
2.请描述顺序存储和链式存储的区别
顺序存储:内存中用一组地址连续的存储单元存储线性表(连续地址存储)
链式存储:内存中用一组任意的存储单元存储线性表(任意地址存储)
3.请尝试自己实现一个双向链表,并提供以下方法和属性:数据的个数,头节点,尾节点,增加数据到链表最后,删除指定位置节点
链表相关代码:
/// <summary>
/// 链表节点
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
class LinkedNode<T>
{
public T value;
public LinkedNode<T> frontNode;//上一个链表节点
public LinkedNode<T> nextNode;//下一个链表节点
public LinkedNode(T value)
{
this.value = value;
}
}
/// <summary>
/// 链表
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
class LinkedList<T>
{
private int count = 0;
private LinkedNode<T> head;
private LinkedNode<T> last;
public LinkedNode<T> Head {
get {
return head; } }
public LinkedNode<T> Last {
get {
return last; } }
public int Count {
get {
return count; } }
public void Add(T value)
{
LinkedNode<T> node = new LinkedNode<T>(value);
if (head == null)
{
head = node;
last = node;
}
else
{
//添加一个数据,添加到尾部
//让尾部的下一个节点等于要加入的节点
last.nextNode = node;
//要加入的节点的上一步节点等于尾部节点
node.frontNode = last;
//尾部节点替换为当前加入的节点
last = node;
}
++count;//添加了一个节点
}
public void RemoveAt(int index)
{
//不能越界
if (index >= count || index < 0)
{
Console.WriteLine("只有{0}个节点,请输入合法位置", count);
return;
}
int tempCount = 0;
LinkedNode<T> tempNode = head;
while (true)
{
//如果是要移除的节点,那么直接移除
if (tempCount == index)
{
//如果是头节点,那么头节点就等于下一个节点
if (index==0)
{
head = head.nextNode;
}else if (index == count - 1)
{
//如果是尾节点,那么让尾节点的上一节点为尾节点
last = last.frontNode;
}
//如果是中部节点
if (tempNode.frontNode != null)
{
//如果上一个节点不为空。则让上一个节点的下一个节点等于自身的下一个节点
tempNode.frontNode.nextNode = tempNode.nextNode;
}
if (tempNode.nextNode != null)
{
//如果下一个节点不为空,则让下一个节点的上一个节点等于自身的上一个节点
tempNode.nextNode.frontNode = tempNode.frontNode;
}
//移除了一个元素,少一截
--count;
break;
}
//每次循环过后临时节点等于下一节点
tempNode = tempNode.nextNode;
++tempCount;
}
}
}
主函数调用:
LinkedList<int> link = new LinkedList<int>();
link.Add(1);
link.Add(2);
link.Add(3);
link.Add(4);
LinkedNode<int> node=link.Head;
while (node != null)
{
Console.WriteLine(node.value);
node = node.nextNode;
}
Console.WriteLine("********************");
link.RemoveAt(2);
node = link.Head;
while (node != null)
{
Console.WriteLine(node.value);
node = node.nextNode;
}
运行结果:
1
2
3
4
********************
1
2
4
第20课 LinkedList知识点
1.使用Linkedlist,向其中加入10个随机整形变量,正向遍历一次打印出信息,反向遍历一次打印出信息
LinkedList<int> linkedList = new LinkedList<int>();
Random r = new Random();
for (int i = 0; i < 10; i++)
{
linkedList.AddLast(r.Next(1, 101));
}
LinkedListNode<int> nowNode = linkedList.First;
while (nowNode != null)
{
Console.WriteLine(nowNode.Value);
nowNode = nowNode.Next;
}
Console.WriteLine("********************");
nowNode = linkedList.Last;
while (nowNode != null)
{
Console.WriteLine(nowNode.Value);
nowNode = nowNode.Previous;
}
第24课 委托 知识点
1.一家三口,妈妈做饭,爸爸妈妈和孩子都要吃饭,用委托模拟做饭——>开饭——>吃饭的过程
//一家三口,妈妈做饭,爸爸妈妈和孩子都要吃饭
//用委托模拟做饭——>开饭——>吃饭的过程
abstract class Person
{
public abstract void Eat();
}
class Mother : Person
{
public Action beginEat;
public override void Eat()
{
Console.WriteLine("妈妈吃饭");
}
public void DoFood()
{
Console.WriteLine("妈妈做饭");
Console.WriteLine("妈妈做饭做好了");
//执行委托函数
if(beginEat != null)
{
beginEat();
}
}
}
class Father:Person
{
public override void Eat()
{
Console.WriteLine("爸爸吃饭");
}
}
class Son:Person
{
public override void Eat()
{
Console.WriteLine("孩子吃饭");
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("委托练习题");
Mother m = new Mother();
Father f = new Father();
Son s = new Son();
//告诉妈妈 一会做好了 我要吃
m.beginEat += f.Eat;
m.beginEat += s.Eat;
m.beginEat += m.Eat;
//做饭
m.DoFood();
}
}
2.怪物死亡后,玩家要加10块钱,界面要更新数据,成就要累加怪物击杀数,请用委托来模拟实现这些功能,只用写核心逻辑表现这个过程,不用写的太复杂
//怪物死亡后,玩家要加10块钱,界面要更新数据
//成就要累加怪物击杀数,请用委托来模拟实现这些功能
//只用写核心逻辑表现这个过程,不用写的太复杂
class Monster
{
//当怪物死亡时 把自己作为参数传出去
public Action<Monster> deadDoSomthing;
//怪物成员变量 特征 价值多少钱
public int money = 10;
public void Dead()
{
Console.WriteLine("怪物死亡");
if(deadDoSomthing != null)
{
deadDoSomthing(this);
}
//一般情况下 委托关联的函数 有加 就有减(或者直接清空)
deadDoSomthing = null;
}
}
class Player
{
private int myMoney = 0;
public void MonsterDeadDoSomthing(Monster m)
{
myMoney += m.money;
Console.WriteLine("现在有{0}元钱", myMoney);
}
}
class Panel
{
private int nowShowMoney = 0;
public void MonsterDeadDo(Monster m)
{
nowShowMoney += m.money;
Console.WriteLine("当前面板显示{0}元钱", nowShowMoney);
}
}
class CJ
{
private int nowKillMonsterNum = 0;
public void MonsterDeadDo(Monster m)
{
nowKillMonsterNum += 1;
Console.WriteLine("当前击杀了{0}怪物", nowKillMonsterNum);
}
}
class Program
{
static void Main(string[] args)
{
Monster monster = new Monster();
Player p = new Player();
Panel panel = new Panel();
CJ cj = new CJ();
monster.deadDoSomthing += p.MonsterDeadDoSomthing;
monster.deadDoSomthing += panel.MonsterDeadDo;
monster.deadDoSomthing += cj.MonsterDeadDo;
monster.Dead();
monster.Dead();
Monster monster2 = new Monster();
monster2.deadDoSomthing += p.MonsterDeadDoSomthing;
monster2.deadDoSomthing += panel.MonsterDeadDo;
monster2.deadDoSomthing += cj.MonsterDeadDo;
monster2.Dead();
}
}
第26课 事件 知识点
1.有一个热水器,包含一个加热器,一个报警器,一个显示器,我们给热水器通上电,当水温超过95度时,1.报警器会开始发出语音,告诉你谁的温度。2.显示器也会改变水温提示,提示水已经烧开了
写的不好,仅供参考
/// <summary>
/// 热水器
/// </summary>
class Calorifier
{
public static event Action<int> MyEvent;
public void BeginPower()
{
Heater heater = new Heater();
heater.BeginHeater();
}
public static void CallEvent(int temp)
{
MyEvent?.Invoke(temp);
}
}
/// <summary>
/// 加热器
/// </summary>
class Heater
{
int temp = 80;
public void BeginHeater()
{
while (true)
{
if (temp < 95)
{
temp++;
Console.WriteLine("加热!!!\t"+temp);
}
if (temp >= 95)
{
//报警器会开始发出语音,告诉你谁的温度
Alarm alarm = new Alarm();
//显示器也会改变水温提示,提示水已经烧开了
Monitor monitor = new Monitor();
Calorifier.CallEvent(temp);
break;
}
}
}
}
/// <summary>
/// 报警器
/// </summary>
class Alarm
{
public Alarm()
{
Calorifier.MyEvent += AlarmBegin;
}
private void AlarmBegin(int temp)
{
Console.WriteLine("发出报警声!!!"+temp);
}
}
/// <summary>
/// 显示器
/// </summary>
class Monitor
{
public Monitor()
{
Calorifier.MyEvent += MonitorBegin;
}
private void MonitorBegin(int temp)
{
Console.WriteLine("当前温度:" + temp+"水开了,已停止加热");
}
}
主函数调用:
Calorifier calor = new Calorifier();
calor.BeginPower();
运行结果:
加热!!! 81
加热!!! 82
加热!!! 83
加热!!! 84
加热!!! 85
加热!!! 86
加热!!! 87
加热!!! 88
加热!!! 89
加热!!! 90
加热!!! 91
加热!!! 92
加热!!! 93
加热!!! 94
加热!!! 95
发出报警声!!!95
当前温度:95水开了,已停止加热