二叉树—顺序结构存储(前序、中序、后序、层序)二叉排序树的添加、查找、删除数据

128 阅读6分钟

目录

1、什么是树?(数据结构的一种)

 2、二叉树

3、二叉树—顺序结构存储

a.创建名字为BiTree的树类

b.创建Test类为主要脚本:

4、二叉排序树—链式存储

a.创建BSNode树类

b.创建BSTree结点类

c.创建Test类为主要脚本


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();//中序遍历
    }
}