赞
踩
由于研究生阶段的需要,需要系统学习C#语言,为了将最近学习的东西进行一个总结,偶然间想到了本科写的那个动物识别系统,用C语言写的很简单,只是用了简单的if…else语句,这里也是简单的用C#语言进行了一个复现。原来的C语言版本在这里:动物识别系统C语言版
有如下规则库,用户来选择这些条件,根据用户输入的条件来判断这是一种什么动物:
编号 | IF条件 | 推论 |
---|---|---|
R1 | 有毛 | 哺乳动物 |
R2 | 有奶 | 哺乳动物 |
R3 | 有羽毛 | 鸟 |
R4 | 会飞 & 会下蛋 | 鸟 |
R5 | 吃肉 | 食肉动物 |
R6 | 有犬齿 & 有爪 & 眼盯前方 | 食肉动物 |
R7 | 哺乳动物 & 有蹄 | 有蹄类动物 |
R8 | 哺乳动物 & 反刍动物 | 有蹄类动物 |
R9 | 哺乳动物 & 食肉动物 & 黄褐色 & 暗斑点 | 金钱豹 |
R10 | 哺乳动物 & 食肉动物 & 黄褐色 & 黑色条纹 | 虎 |
R11 | 有蹄类动物 & 长脖子 & 长腿 & 暗斑点 | 长颈鹿 |
R12 | 有蹄类动物 & 黑色条纹 | 斑马 |
R13 | 鸟 & 不会飞 & 长脖子 & 长腿 & 黑白二色 | 鸵鸟 |
R14 | 鸟 & 不会飞 & 会游泳 & 黑白二色 | 企鹅 |
R15 | 鸟 & 善飞 | 信天翁 |
如果用一个图来表示就是这样的:
图中,食肉动物那一列,需要同时满足时哺乳动物才能继续往下推出时金钱豹或老虎。
我采用的是字典作为知识库和规则库的存储结构,知识库的结构是:
Dictionary<int, string> _knowledgeBase = new Dictionary<int, string>()
{
{1, "有毛发"},{2, "有奶 "},{3 ,"有羽毛"},{4 ,"会飞 "},
{5 ,"会下蛋"},{6 ,"眼盯前方"},{7 ,"有蹄 "},{8 ,"反刍动物"},
{9 ,"吃肉 "},{10 ,"有犬齿"},{11 ,"有爪"},{12 ,"长脖子"},
{13 ,"长腿"},{14 ,"有暗斑点"},{15 ,"有黑色条纹"},{16 ,"黄褐色"},
{17 ,"不会飞"},{18 ,"黑白二色"},{19 ,"会游泳"},{20 ,"擅飞"}
};
这样知识库条件的序号就一一对应上了,也方便输出。
规则库的结构是:
Dictionary<int[], string> _ruleBase = new Dictionary<int[], string>();
之所以选择int数组作为其存储结构,在用户输入后,把用户输入的条件序号转换为一个int数组,这样就可以直接看字典中是否有这个键,当然要对这个int数组进行一个约束,因为对于判断数组相同的要求是:1.数组元素个数相同。2.对应位置上的元素相同,我这里采用的方式是对int数组进行一个排序,即使用户不是按照顺序输入的条件,也能进行判断。
遇到的问题:因为int数组是引用类型,存储的是地址,因次即使Dictionary中存在和用户输入相同的键,也不能进行判断,用户输入的条件数组的地址和Dictionary中键的地址是不一样的,比如:
Dictionary<int[], string> _rule = new Dictionary<int[], string>();
_rule.Add(new int[] { 1, 2, 3 }, "鸟");
int[] rule = { 1, 2, 3 };
bool result = _rule.ContainsKey(rule); //result的结果为false
result的结果居然是false,那就是引用类型的缘故,解决方法:需要重写Equals()方法,以及重写GetHashCode()方法。
参考自文章:C#中,对于Dictionary字典类型,使用引用类型做Key的注意事项
using System; using System.Collections.Generic; using System.Linq; namespace AnimalSystem { // 使用引用类型作为字典的Key,需要重写Equals方法和GetHashCode()方法 public class ArrayExtend { int[] arr; string content = ""; public void Init(int[] a) { int count = a.Count(); arr = new int[count]; for (int i = 0; i < count; i++) { arr[i] = a[i]; content += arr[i] + ","; } } public override bool Equals(object obj) { ArrayExtend temp22 = (ArrayExtend)obj; bool flag = true; for (int i = 0; i < arr.Count(); i++) { if (arr[i] != temp22.arr[i]) flag = false; } return flag; } public override int GetHashCode() { return content.GetHashCode(); } } class Program { static void Main(string[] args) { // 准备知识库 Dictionary<int, string> _knowledgeBase = new Dictionary<int, string>() { {1, "有毛发"},{2, "有奶 "},{3 ,"有羽毛"},{4 ,"会飞 "}, {5 ,"会下蛋"},{6 ,"眼盯前方"},{7 ,"有蹄 "},{8 ,"反刍动物"}, {9 ,"吃肉 "},{10 ,"有犬齿"},{11 ,"有爪"},{12 ,"长脖子"}, {13 ,"长腿"},{14 ,"有暗斑点"},{15 ,"有黑色条纹"},{16 ,"黄褐色"}, {17 ,"不会飞"},{18 ,"黑白二色"},{19 ,"会游泳"},{20 ,"擅飞"} }; // 这里使用的是int[]数组类型作为字典的Key,其使用方法引用自文章 // https://www.cnblogs.com/WangSong-Gemini/p/16407833.html // 准备规则库(命名规则:第一个数字代表动物编号,第二个数字代表该动物的条件编号) Dictionary<ArrayExtend, string> _ruleBase = new Dictionary<ArrayExtend, string>(); ArrayExtend a11 = new ArrayExtend(); ArrayExtend a12 = new ArrayExtend(); ArrayExtend a13 = new ArrayExtend(); ArrayExtend a14 = new ArrayExtend(); ArrayExtend a21 = new ArrayExtend(); ArrayExtend a22 = new ArrayExtend(); ArrayExtend a23 = new ArrayExtend(); ArrayExtend a24 = new ArrayExtend(); ArrayExtend a31 = new ArrayExtend(); ArrayExtend a32 = new ArrayExtend(); ArrayExtend a33 = new ArrayExtend(); ArrayExtend a34 = new ArrayExtend(); ArrayExtend a41 = new ArrayExtend(); ArrayExtend a42 = new ArrayExtend(); ArrayExtend a43 = new ArrayExtend(); ArrayExtend a44 = new ArrayExtend(); ArrayExtend a51 = new ArrayExtend(); ArrayExtend a52 = new ArrayExtend(); ArrayExtend a61 = new ArrayExtend(); ArrayExtend a62 = new ArrayExtend(); ArrayExtend a71 = new ArrayExtend(); ArrayExtend a72 = new ArrayExtend(); a11.Init(new int[] { 1, 7, 15 }); a12.Init(new int[] { 2, 7, 15 }); a13.Init(new int[] { 1, 8, 15 }); a14.Init(new int[] { 2, 8, 15 }); // 斑马 a21.Init(new int[] { 1, 7, 12, 13, 14 }); a22.Init(new int[] { 2, 7, 12, 13, 14 }); a23.Init(new int[] { 1, 8, 12, 13, 14 }); a24.Init(new int[] { 2, 8, 12, 13, 14 }); // 长颈鹿 a31.Init(new int[] { 1, 9, 14, 16 }); a32.Init(new int[] { 2, 9, 14, 16 }); a33.Init(new int[] { 1, 6, 10, 11, 14, 16 }); a34.Init(new int[] { 2, 6, 10, 11, 14, 16 }); // 金钱豹 a41.Init(new int[] { 1, 9, 15, 16 }); a42.Init(new int[] { 2, 9, 15, 16 }); a43.Init(new int[] { 1, 6, 10, 11, 15, 16 }); a44.Init(new int[] { 2, 6, 10, 11, 15, 16 }); // 虎 a51.Init(new int[] { 3, 12, 13, 17, 18 }); a52.Init(new int[] { 4, 5, 12, 13, 17, 18 }); // 鸵鸟 a61.Init(new int[] { 3, 20 }); a62.Init(new int[] { 4, 5, 20 }); // 信天翁 a71.Init(new int[] { 3, 17, 18, 19 }); a72.Init(new int[] { 4, 5, 17, 18, 19 }); // 企鹅 _ruleBase.Add(a11, "斑马"); _ruleBase.Add(a12, "斑马"); _ruleBase.Add(a13, "斑马"); _ruleBase.Add(a14, "斑马"); _ruleBase.Add(a21, "长颈鹿"); _ruleBase.Add(a22, "长颈鹿"); _ruleBase.Add(a23, "长颈鹿"); _ruleBase.Add(a24, "长颈鹿"); _ruleBase.Add(a31, "金钱豹"); _ruleBase.Add(a32, "金钱豹"); _ruleBase.Add(a33, "金钱豹"); _ruleBase.Add(a34, "金钱豹"); _ruleBase.Add(a41, "虎"); _ruleBase.Add(a42, "虎"); _ruleBase.Add(a43, "虎"); _ruleBase.Add(a44, "虎"); _ruleBase.Add(a51, "鸵鸟"); _ruleBase.Add(a52, "鸵鸟"); _ruleBase.Add(a61, "信天翁"); _ruleBase.Add(a62, "信天翁"); _ruleBase.Add(a71, "企鹅"); _ruleBase.Add(a72, "企鹅"); // 输出知识库 Console.WriteLine("===============================动物识别系统规则库==============================="); foreach (var item in _knowledgeBase) { Console.Write("{0}:{1}\t", item.Key, item.Value); if (item.Key % 5 == 0) // 控制换行的逻辑 { Console.WriteLine(); } } // 获取用户输入 Console.WriteLine("================================================================================"); Console.WriteLine("请输入已知条件(用空格分开),按回车结束:"); // 获取用户输入 string userInput = Console.ReadLine(); // 拆分用户输入 string[] inputx = userInput.Split(' '); // 将用户输入的字符串转换成int数组 int[] inputy = new int[inputx.Length]; for (int i = 0; i < inputy.Length; i++) { inputy[i] = Convert.ToInt32(inputx[i]); } // 反馈给用户检查 Console.WriteLine("================================================================================"); Console.Write("请检查您的输入:"); foreach(var item in inputy) { Console.Write(item + " "); } Console.WriteLine(); Console.Write("Y/N?: "); string inputCheck = Console.ReadLine(); if(inputCheck.Equals("Y") || inputCheck.Equals("y")) { Console.WriteLine("OK"); // 将用户的输入排个序 SortArray(inputy); } else if(inputCheck.Equals("N") || inputCheck.Equals("n")) { // 实现跳转到重新输入的逻辑?(待实现) Console.WriteLine("Error"); } else { Console.WriteLine("请重新输入:"); throw new Exception("输入错误"); // 跳转到重新输入的逻辑? } Console.WriteLine("================================================================================"); // 进行判断的逻辑 ArrayExtend inputUser = new ArrayExtend(); inputUser.Init(inputy); try { // 如果当前规则库中没有存在这个规则在这里就会抛出异常 string result = _ruleBase[inputUser]; Console.WriteLine("根据您输入的条件,可以推断出这个动物是:" + result); } catch (Exception) { Console.WriteLine("根据您的输入条件,无法判断这是一种什么动物。"); } Console.ReadLine(); } // 将数组元素从小到大排序(用户的输入可能不是按照从小到大的顺序,根据规则库的存储结构,需要将用户的输入进行从小到大的排序) static void SortArray(int[] arr) { for (int i = 0; i < arr.Length-1; i++) { for (int j = i + 1; j < arr.Length; j++) { if (arr[j] < arr[i]) { int temp = arr[j]; arr[j] = arr[i]; arr[i] = temp; } } } } } }
代码还有很多不完善的地方,比如说实现反复推理,不是每次运行推理结束后又要点一次运行,又比如说在不小心输入错误了,实现重新输入等等。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。