C#二叉树学习总结1:二叉树的前、中、后、层序遍历以及二叉查找树的增删改查算法

为了简化二叉查找树的删除操作,我将节点按如下定义:

 class Node
    {
        public int data;
        public Node rChild;
        public Node lChild;
        //增加父节点,目的是为了便于删出节点的操作
        public Node parent;
        public Node() { }
        public Node(int data)
        {
            this.data = data;
            this.rChild = null;
            this.lChild = null;
            this.parent = null;
        }
    }

BST类及其相关方法如下,每个操作都有较为详细的注释:

class BST
    {
        public Node rootnode;
        //本来应该构建一个普通树作为示例,但是不方便
        //不妨就直接构建二叉查找树作为示例
        public void AddNodeToBST(BST tree, int data)
        {
            Node newnode = new Node(data);
            if(tree.rootnode == null)
            {
                tree.rootnode = newnode;
                return;
            }
            Node current = tree.rootnode;
            while (true)
            {
                if (data < current.data)
                {
                    if(current.lChild == null)
                    {
                        current.lChild = newnode;
                        newnode.parent = current;
                        return;
                    }
                    current = current.lChild;
                }
                else
                {
                    if (current.rChild == null)
                    {
                        current.rChild = newnode;
                        newnode.parent = current;
                        return;
                    }
                    current = current.rChild;
                }
            }
        }
        
        //前序遍历二叉树
        public void PreOrder(Node node)
        {
            if(node != null)
            {
                Write(node.data + " ");
                PreOrder(node.lChild);
                PreOrder(node.rChild);
            }
        }

        //中序遍历二叉树
        public void MiddleOrder(Node node)
        {
            if (node != null)
            {
                MiddleOrder(node.lChild);
                Write(node.data + " ");
                MiddleOrder(node.rChild);
            }
        }
        
        //后续遍历二叉树
        public void AfterOrder(Node node)
        {
            if(node != null)
            {
                AfterOrder(node.lChild);
                AfterOrder(node.rChild);
                Write(node.data + " ");
            }
        }

        //层序遍历二叉树
        public void LevelOrder(Node node)
        {
            Queue<Node> queue = new Queue<Node>();
            if (node == null) return;
            queue.Enqueue(node);
            while (queue.Any())
            {
                Node item = queue.Dequeue();
                Write(item.data + " ");
                if(item.lChild != null)
                {
                    queue.Enqueue(item.lChild);
                }
                if (item.rChild != null)
                {
                    queue.Enqueue(item.rChild);
                }
            }
        }

        //二叉树增删改查之增
        //其实构建二叉树的过程就是增的过程,改某个节点值就是查找到然后修改data值,所以就不再赘述

        //二叉树 查找 非递归版本
        public bool FindInBST1(Node rootnode , int data)
        {
            int count = 1;
            Node current = rootnode;
            while (true)
            {
                if (current.data == data)
                {
                    WriteLine("找到了,在树的第{0}层", count);
                    return true;
                }
                if(data <current.data)
                {
                    if(current.lChild == null)
                    {
                        return false;
                    }
                    count++;
                    current = current.lChild;
                }
                else
                {
                    if(current.rChild == null)
                    {
                        return false;
                    }
                    count++;
                    current = current.rChild;
                }
            }
            
        }

        //二叉树 查找 递归版本
        public bool FindInBST2(Node rootnode, int data)
        {
            Node current = rootnode;
            if(current == null)
            {
                return false;
            }
            else if(current.data == data)
            {
                return true;
            }
            else if(data <current.data)
            {
                return FindInBST2(current.lChild, data);
            }
            else
            {
                return FindInBST2(current.rChild, data);
            }
        }

        //二叉树 删除 分为三种情况1.为叶节点 2.只有左或者右子节点 3.左右子节点都有
        public void DeleteNode( Node rootnode,int deletedata)
        {
            //先找到该节点
            Node current = rootnode;
            if(current.data == deletedata)
            {
                Delete(current);
            }
            else if(current == null)
            {
                WriteLine("要删除的节点不存在");
                return;
            }
            else if(deletedata < current.data)
            {
                DeleteNode(current.lChild, deletedata);
            }
            else
            {
                DeleteNode(current.rChild, deletedata);
            }
        }
        public void Delete(Node deletenode)
        {
            if(deletenode.lChild == null && deletenode.rChild == null)
            {
                //说明是叶子节点,直接删除就好
                if(deletenode.parent.lChild == deletenode)
                {
                    deletenode.parent.lChild = null;
                }
                else
                {
                    deletenode.parent.rChild = null;
                }
            }
            else if(deletenode.lChild == null && deletenode.rChild != null)
            {
                //说明有右节点,没有左节点
                Node temp = deletenode;
                deletenode = deletenode.rChild;
                //直接用该节点的右子节点替换该节点,但是还有两点需要改
                //1.新节点的父节点 2.删除节点的父节点的子节点指向
                deletenode.parent = temp.parent;
                if(temp == temp.parent.lChild)
                {
                    //说明父节点的左子节点指向待删除的节点
                    temp.parent.lChild = deletenode;
                }
                else
                {
                    //说明父节点的右子节点指向待删除的节点
                    temp.parent.rChild = deletenode;
                }
            }
            else if(deletenode.rChild == null && deletenode.lChild != null)
            {
                //说明有左节点,没有右节点
                Node temp = deletenode;
                deletenode = deletenode.lChild;
                //直接用该节点的右子节点替换该节点,但是还有两点需要改
                //1.新节点的父节点 2.删除节点的父节点的子节点指向
                deletenode.parent = temp.parent;
                if (temp == temp.parent.lChild)
                {
                    //说明父节点的左子节点指向待删除的节点
                    temp.parent.lChild = deletenode;
                }
                else
                {
                    //说明父节点的右子节点指向待删除的节点
                    temp.parent.rChild = deletenode;
                }
            }
            else
            {
                //其他情况说明左右子树都存在,此时可以寻找它的中序遍历的前一个节点作为替代,这样就是寻找它的左子树最右边的一个节点
                //或者可以寻找它的中序遍历的后一个节点作为替代,这样寻找它的右子树最左边的一个节点
                //这里采用上述说的第一个方式
                Node current = deletenode.lChild;
                while (true)
                {
                    if (current.rChild != null)
                    {
                        current = current.rChild;
                    }
                    else { break; }
                }
                //删除该节点并不改变该节点的左右子节点和父节点的关系,所以替换值就可以了,然后转化为删除替换节点
                deletenode.data = current.data;
                Delete(current);
            }
        }
        
    }

测试如下:

class Program
    {
        static void Main(string[] args)
        {
            int[] arr = { 62, 58, 88, 47, 73, 99, 35, 51, 93, 37, 49, 52, 38, 48};
            BST tree = new BST();
            for (int i = 0; i < arr.Length; i++)
            {
                tree.AddNodeToBST(tree,arr[i]);
            }

            WriteLine("前序遍历");
            tree.PreOrder(tree.rootnode);
            WriteLine();
            WriteLine("中序遍历");
            tree.MiddleOrder(tree.rootnode);
            WriteLine();
            WriteLine("后序遍历");
            tree.AfterOrder(tree.rootnode);
            WriteLine();
            WriteLine("按层遍历");
            tree.LevelOrder(tree.rootnode);
            WriteLine();

            //查找
            tree.FindInBST1(tree.rootnode, 93);
            WriteLine(tree.FindInBST2(tree.rootnode, 37));

            //删除
            Write("请输入您要删除的数:");
            int deletenum = int.Parse(ReadLine());
            if(deletenum == tree.rootnode.data)
            {
                //如果删除根节点,那么就全部删除吧
                tree.rootnode = null;
            }
            else
            {
                tree.DeleteNode(tree.rootnode, deletenum);
            }
            tree.MiddleOrder(tree.rootnode);

        }
    }

结果显示:

如果有问题请留言。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值