目录
1、什么是树?(数据结构的一种)
2、二叉树
3、二叉树—顺序结构存储
a.创建名字为BiTree的树类
/****************************************************
* 功能:定义数据结构
*****************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BiTree<T>//使用泛型
{
//如果一个结点是空的话,那么这个结点所在的数组位置。设置为-1
private T[] date;//数据
private int count = 0;//当前数据的个数
/// <summary>
/// 构造方法
/// </summary>
/// <param name="capacity"></param>
public BiTree(int capacity)//这个参数是当前二叉树的容量,容量:最多可以存储的数据个数,数量count代表当前存储了多少个数据
{
date = new T[capacity];//构造数组
}
public bool Add(T item)//判断是否添加数据成功
{
if (count>=date.Length)
return false;
date[count] = item;
count++;
return true;
}
/// <summary>
/// 前序遍历 每个递归都需要有终止条件
/// </summary>
public void FirstTraversal()
{
FirstTraversal(0);//封装方法
}
private void FirstTraversal(int index)
{
if (index>=count)return;
//得到要遍历的结点的编号
int number = index + 1;
if (date[index].Equals(-1))return;//判断数组数据是否存在 不存在时存储的值为-1
Debug.Log(date[index]+" ");//访问遍历当前结点
int leftNumber = number * 2;//得到左子结点的编号
int rightNumber = number * 2+1;//得到右子结点的编号
FirstTraversal(leftNumber-1);//遍历 相当于递归调用
FirstTraversal(rightNumber-1);//先遍历左结点再遍历右结点
}
/// <summary>
/// 中序遍历
/// </summary>
public void MiddleTraversal()
{
MiddleTraversal(0);//给外界提供访问的方法
}
private void MiddleTraversal(int index)
{
if (index >= count) return;
//得到要遍历的结点的编号
int number = index + 1;
if (date[index].Equals(-1)) return;//判断数组数据是否存在 不存在时存储的值为-1
//输出之前先遍历左子节点
int leftNumber = number * 2;//得到左子结点的编号
int rightNumber = number * 2 + 1;//得到右子结点的编号
MiddleTraversal(leftNumber - 1);//遍历 相当于递归调用
Debug.Log(date[index] + " ");//访问遍历当前结点
MiddleTraversal(rightNumber - 1);//再遍历右结点
}
/// <summary>
/// 后序遍历
/// </summary>
public void LastTraversal()
{
LastTraversal(0);//给外界提供访问的方法
}
private void LastTraversal(int index)
{
if (index >= count) return;
//得到要遍历的结点的编号
int number = index + 1;
if (date[index].Equals(-1)) return;//判断数组数据是否存在 不存在时存储的值为-1
//输出之前先遍历左子节点
int leftNumber = number * 2;//得到左子结点的编号
int rightNumber = number * 2 + 1;//得到右子结点的编号
LastTraversal(leftNumber - 1);//遍历 相当于递归调用
LastTraversal(rightNumber - 1);//再遍历右结点
Debug.Log(date[index] + " ");//最后访问遍历当前结点
}
/// <summary>
/// 层序遍历
/// </summary>
public void LayerTraversal()
{
LayerTraversal(0);//给外界提供访问的方法
}
private void LayerTraversal(int index)
{
for (int i = 0; i < count; i++)
{
if (date[i].Equals(-1)) continue;
Debug.Log(date[index]+" ");
}
}
}
b.创建Test类为主要脚本:
/****************************************************
* 功能:二叉树顺序结构存储
*****************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
void Start()
{
Suanfa();
}
void Suanfa()
{
char[] date = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};//需要存储的数据
BiTree<char> tree = new BiTree<char>(10);//声明一个集合
for (int i = 0; i < date.Length; i++)//遍历添加数据到二叉树中
{
tree.Add(date[i]);
}
tree.FirstTraversal();
tree.MiddleTraversal();
tree.LastTraversal();
tree.LayerTraversal();
}
}
4、二叉排序树—链式存储
二叉排序树,又称为二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树。
若它的左子树不为空,则左子树上所有的结点的值均小于根结构的值;
若它的右子树不为空,则右字数上所有结点的值均大于它的根结点的值;
它的左右子树也分别为二叉排序树。
a图 b图
c图
a.创建BSNode树类
/****************************************************
* 功能:结点类 二叉树链式存储
*****************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BSNode
{
public BSNode LeftChild { get; set; } //左孩子
public BSNode RightChild { get; set; }//右孩子
public BSNode Parent { get; set; }//父亲
public int Date { get; set; }
//构造方法
public BSNode()
{
}
//传递数据的构造方法
public BSNode(int item)
{
this.Date = item;
}
}
b.创建BSTree结点类
/****************************************************
* 功能:树类的定义 采用递归调用
*****************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BSTree
{
private BSNode root = null; //保存跟结点就可以访问到其下面的所有子结点
public void Add(int item) //添加数据
{
BSNode newNode = new BSNode(item); //根据数据创建结点
if (root == null) //说明当前树是空树,当前结点就是根结点
{
root = newNode;
}
else
{
BSNode temp = root; //定义临时结点
//从根结点开始遍历,遍历到叶子结点,放到叶子结点的下面
while (true)
{
if (item >= temp.Date) //判断当前数据与temp大小,大则放在temp右边
{
if (temp.RightChild == null) //右结点等于空则直接放在右边
{
temp.RightChild = newNode; //设置下父子
newNode.Parent = temp;
break;
}
else //右结点不等于空时,继续向下找
{
temp = temp.RightChild; //右结点指向temp 然后继续遍历查找
}
}
else //放在temp的左边
{
if (temp.LeftChild == null) //判断左孩子是否为空
{
temp.LeftChild = newNode; //设置下父子
newNode.Parent = temp;
break;
}
else
{
temp = temp.LeftChild; //左结点设置给temp 然后继续遍历查找
}
}
}
}
}
/// <summary>
/// 中序遍历
/// </summary>
public void MiddleTraversal()
{
MiddleTraversal(root); //外部访问的方法
}
private void MiddleTraversal(BSNode node) //表示从哪个结点开始遍历
{
if (node == null) return;
MiddleTraversal(node.LeftChild); //遍历左结点
Debug.Log(node.Date + " "); //输出当前数据
MiddleTraversal(node.RightChild); //遍历右结点
}
/// <summary>
/// 查找item是否存在根结点中 递归调用
/// </summary>
public bool Find(int item)
{
//第一种方式
//return Find(item, root);
//第二种方式
BSNode temp = root;//临时结点
while (true)
{
if (temp == null) return false;
if (temp.Date == item) return true;
if (item>temp.Date)
{
temp = temp.RightChild;
}
else
{
temp = temp.LeftChild;
}
}
}
private bool Find(int item, BSNode node) //判断当前数据item是否存在于要查找的结点node中
{
if (node == null) return false;
if (node.Date == item)
{
return true; //找到
}
else
{
if (item>node.Date)
{
return Find(item, node.RightChild);
}
else
{
return Find(item, node.LeftChild);
}
}
}
/// <summary>
/// 判断item是否删除成功
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Delete(int item)
{
BSNode temp = root;
while (true)//进行搜索查找
{
if (temp == null) return false;
if (temp.Date == item)//找到 删除temp
{
Delete(temp);
return true;
}
if (item > temp.Date)
{
temp = temp.RightChild;
}
else
{
temp = temp.LeftChild;
}
}
}
/// <summary>
/// 删除结点的方法 把删除的结点node传递进去
/// </summary>
/// <param name="node"></param>
public void Delete(BSNode node)
{
if (node.LeftChild == null && node.RightChild == null) //叶子结点 左右孩子都为空
{
//删除叶子结点
if (node.Parent == null) //当前要删除的结点为根结点
{
root = null;
}
else if (node.Parent.LeftChild == node) //左孩子 如a图73 93
{
node.Parent.LeftChild = null; //删除父类对自己的引用
}
else if (node.Parent.RightChild == node) //如a图37 51
{
node.Parent.RightChild = null;
}
return;
}
//仅有右子树的结点
if (node.LeftChild == null && node.RightChild != null)
{
node.Date = node.RightChild.Date; //如b图把37的数据给35
node.RightChild = null; //然后删除37所在的引用
return;
}
//仅有左子数的结点
if (node.LeftChild != null && node.RightChild == null)
{
node.Date = node.LeftChild.Date; //把93的数据给99
node.LeftChild = null; //删除93所在的引用
return;
}
//如c图,要删除47,开始的temp(51)指向node(47)的右子树的根结点,然后找51下面的左子结点(49,48),找到左子结点最小的值
BSNode temp = node.RightChild;
while (true)
{
if (temp.LeftChild != null) //左子结点不为空 一直找到左子结点
{
temp = temp.LeftChild;
}
else//temp=48时 左子结点为空 循环结束
{
break;
}
}
//如c图,48是叶子结点,但不一定是最小的,如48的右子结点可能为48.5 要么是叶子结点 要么是只有一个子树的结点
node.Date = temp.Date;//48的值赋值给47 然后递归调用方法删除48
Delete(temp);//此时node=48,temp=48.5,把48.5赋值给48,删除48
}
}
c.创建Test类为主要脚本
/****************************************************
* 功能:测试
*****************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
void Start()
{
SuanFa();
}
void SuanFa()
{
BSTree tree = new BSTree();//创建树集合
int[] date = {62, 58, 88, 47, 73, 99, 35, 51, 93, 37};//数据数组
foreach (int t in date)
{
tree.Add(t);//添加数据
}
//tree.MiddleTraversal();//输出中序遍历数据
//Debug.Log(tree.Find(99));//输出判断item是否存在于根结点中
//Debug.Log(tree.Find(100));
tree.Delete(35);//删除35
tree.MiddleTraversal();//中序遍历
}
}