休息了两天,又开始上班了,最后一天班再努力继续学习,在上一章我讲述了泛型类和常规类的区别,这次我们详细再讲讲泛型类和怎么去使用泛型类。
四、创建泛型类(二叉树举例)
泛型类的创建很简单,只要在类的后面加一个<T>就可以了,.net里面也提供了很多现成的泛型类,在System.Collections.Generic的命名空间中,我们也可以自定义自己的泛型类,但在此之前,我们还是得要掌握好一些知识背景。
我们以二叉树理论举例,首先我简单的介绍一下什么叫二叉树,这里不懂得同学可以看看,在下面例子中我会一一画图讲解,对二叉树非常熟悉的同学可以略过,因为这个例子是比较简单而且可能对你来说可能意义不大,可以直接去看下面代码实操。
首先二叉树它是一种递归数据结构,也就是自己调用自己的数据结构,它要么空,要么就包含三个元素:数据(节点),左子树,右子树;左子树和右子树它们本身也是属于一个二叉树,因为可以以它自身做一个节点再延伸出它的左子树、右子树,如下图:
这样就是一个简单的二叉树,它具有一个节点,两个子树,一个左,一个右:
这样看的话左子树就成为了一个节点拥有两个子树,而右子树只有一个子树,这种情况是可以的:
代码实操
1、接下来我们看一下代码是如何实现二叉树,首先我们创建一个树类,并给予它三个属性,一个节点,两个子树,因为子树本身也是个二叉树,它也可以拥有自己的左右子树,所以它的类型为Tree<TItem>
public class Tree<TItem>
{
//节点(值类型或引用类型)
public TItem NodeData { get; set; }
//左子树(类的实例对象,引用类型)
public Tree<TItem> LeftTree { get; set; }
//右子树(类的实例对象,引用类型)
public Tree<TItem> RightTree { get; set; }
}
2、添加构造方法进行初始化
//构造方法初始化
public Tree(TItem item) {
this.NodeData = item;
this.LeftTree = null;
this.RightTree = null;
}
3、添加插入数据方法,左子树情况
public void Insert(TItem newItem) {
//获取当前节点数据
TItem currentNodeValue = this.NodeData;
/比较当前节点数据和要插入的数据两者大小,插入的数据大于节点则返回1,等于则返回0,小于则返回-1这个是由实现compareTo方法的参数类型决定
//返回1的情况也就是插入的数据大于当前节点,插入右子树,遵循左小右大
if (currentNodeValue.CompareTo(newItem) > 0)
{
//若当前节点的左子树为空
if (this.LeftTree == null)
{
//创建新的二叉树,以即将插入的数据为节点
this.LeftTree = new Tree<TItem>(newItem);
}
//若当前左子树不为空,已存在
else
{
//进入该存在的节点再检查一遍
this.LeftTree.Insert(newItem);
}
}
4、在此处我们使用到了CompareTo()这个方法,这是一个用于比较大小的方法,它支持任何参数,如果我们只是Int类型的话,那就用<,>,=这类符号来代替就好,正因为我们是泛型,我们可能遇到一些不是这样常规的值类型,所以我们就运用到了这个方法,这个方法来自于IComparable<T>这个泛型接口,我们要给我们的泛型类添加一个泛型约束来实现这个接口,所以回到顶部修改
public class Tree<TItem> where TItem : IComparable<TItem>
{
.......
}
附加:泛型约束,就是我们在给出类型时,也就是TItem,必须要实现了Icomparable接口方法的类型才可以,例如Int,string这些它们本身就实现了IComparable接口里的CompareTo()方法,如果我们自己写一个类叫Person,这个类没有使用IComparable这个接口也没有实现方法的话,那我们在使用这个泛型类时给它定义成Person类型的时候就会出错如Tree<Person>。
5、补充else,插入右子树的情况
public string WalkTree()
{
//定义一个字符串
string result = "";
//判断左子树是否为空,不为空则赋值给字符串,继续调用WalkTree()直到左右子树都为空
if (this.LeftTree != null)
{
result = this.LeftTree.WalkTree();
}
//显示当前节点的数值
result += $"{this.NodeData.ToString()}";
//判断右子树是否为空,不为空则赋值给字符串,继续调用WalkTree()直到左右子树都为空
if (this.RightTree != null)
{
result += this.RightTree.WalkTree();
}
//返回字符串
return result;
}
插入时的二叉树图解
6、添加WalkTree方法遍历二叉树
//遍历二叉树方法,从左开始
public string WalkTree()
{
//定义一个字符串
string result = " ";
//判断左子树是否为空,不为空则赋值给字符串,继续调用WalkTree()直到左右子树都为空
if (this.LeftTree != null)
{
result = this.LeftTree.WalkTree();
}
//显示节点的数值
result += $"{this.NodeData.ToString()}";
//判断右子树是否为空,不为空则赋值给字符串,继续调用WalkTree()直到左右子树都为空
if (this.RightTree != null)
{
result += this.RightTree.WalkTree();
}
//返回字符串
return result;
}
6、1遍历顺序如下,最好自己动手观察程序的走向
7、最后我们进行测试
class Program
{
static void Main(string[] args)
{
//以3为第一个节点,给tree设定为int类型,int实现了IComparable接口所以允许使用
Tree<int> tree = new Tree<int>(5);
tree.Insert(3);
tree.Insert(10);
tree.Insert(-12);
tree.Insert(4);
tree.Insert(8);
tree.Insert(12);
string treedata = tree.WalkTree();
Console.WriteLine("二叉树遍历出来的数据顺序为:"+treedata);
}
}