C#数据结构-二叉树实现及常见面试题

二叉查找树

二叉排序树,又称为二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树。

  若它的左子树不为空,则左子树上所有的结点的值均小于根结构的值;

  若它的右子树不为空,则右字数上所有结点的值均大于它的根结点的值;

1. 前序、中序、后序、层次遍历

一般会考查非递归版本的实现,频率很高,在下面的代码递归和非递归版本都有实现。

2. 二叉树的镜像

具体实现在下面的代码中。

3. 二叉树的深度

具体实现在下面的代码中。

4. 二叉树是否是平衡二叉树

用后序遍历的方式,遍历二叉树的每一个结点,在遍历每一个结点前,我们已经遍历了它的左右子树。只要在遍历每个结点时,记录它的深度。具体实现在下面的代码中。

5.输入一个整数S,打印二叉树中路径长度和为S的所有路径。从根节点到叶子节点形成一条路径。

6. 树中两个节点的公共祖先

using System;
using System.Collections.Generic;

namespace StructScript
{
    public class BinaryTree<T>
    {
        //根节点
        private TreeNode<T> mRoot;
        //比较器
        private Comparer<T> mComparer;

        public BinaryTree()
        {
            mRoot = null;
            mComparer = Comparer<T>.Default;
        }

        public bool Contains(T value)
        {
            if (value == null)
            {
                throw new ArgumentNullException();
            }
            TreeNode<T> node = mRoot;
            while (node != null)
            {
                int comparer = mComparer.Compare(value, node.Data);
                if (comparer > 0)
                {
                    node = node.RightChild;
                }
                else if (comparer < 0)
                {
                    node = node.LeftChild;
                }
                else
                {
                    return true;
                }
            }
            return false;
        }

        public void Add(T value)
        {
            mRoot = Insert(mRoot, value);
        }

        private TreeNode<T> Insert(TreeNode<T> node, T value)
        {
            if (node == null)
            {
                return new TreeNode<T>(value, 1);
            }
            int comparer = mComparer.Compare(value, node.Data);
            if (comparer > 0)
            {
                node.RightChild = Insert(node.RightChild, value);
            }
            else if (comparer < 0)
            {
                node.LeftChild = Insert(node.LeftChild, value);
            }
            else
            {
                node.Data = value;
            }
            return node;
        }

        public int Count
        {
            get
            {
                return CountLeafNode(mRoot);
            }
        }

        private int CountLeafNode(TreeNode<T> root)
        {
            if (root == null)
            {
                return 0;
            }
            else
            {
                return CountLeafNode(root.LeftChild) + CountLeafNode(root.RightChild) + 1;
            }
        }

        public int Depth
        {
            get
            {
                return GetHeight(mRoot);
            }
        }

        // 二叉树的深度
        private int GetHeight(TreeNode<T> root)
        {
            if (root == null)
            {
                return 0;
            }
            int leftHight = GetHeight(root.LeftChild);
            int rightHight = GetHeight(root.RightChild);
            return leftHight > rightHight ? leftHight + 1 : rightHight + 1;
        }

        // 是否是平衡二叉树
        // 后序遍历二叉树,在遍历左右子树时,
        // 根据左右子树的结点的深度判断是否是平衡二叉树
        public bool IsBlanced(BinaryTree<T> bt)
        {
            int depth = 0;
            return IsBlanced(bt.mRoot, ref depth);
        }

        private bool IsBlanced(TreeNode<T> root, ref int depth)
        {
            if (root == null)
            {
                depth = 0;
                return true;
            }
            int leftDepth = 0;
            int rightDepth = 0;
            if (IsBlanced(root.LeftChild, ref leftDepth)
                && IsBlanced(root.RightChild, ref rightDepth))
            {
                int diff = leftDepth - rightDepth;
                if (diff <= 1 && diff >= -1)
                {
                    depth = 1 + (leftDepth > rightDepth ? leftDepth : rightDepth);
                    return true;
                }
            }
            return false;
        }

        public void MirrorBinaryTree()
        {
            MirrorBinaryTree(mRoot);
        }

        // 二叉树的镜像
        private void MirrorBinaryTree(TreeNode<T> node)
        {
            if(node == null || (node.LeftChild == null && node.RightChild == null))
            {
                return;
            }
            TreeNode<T> tempNode = node.LeftChild;
            node.LeftChild = node.RightChild;
            node.RightChild = tempNode;
            if(node.LeftChild != null)
            {
                MirrorBinaryTree(node.LeftChild);
            }
            if(node.RightChild != null)
            {
                MirrorBinaryTree(node.RightChild);
            }
        }

        // 输入一个整数S,打印二叉树中路径长度和为S的所有路径。
        public void FindPath(int sum)
        {
            Stack<int> stack = new Stack<int>();
            int currentSum = 0;
            FindPath(mRoot, sum, ref currentSum, stack);
        }

        private void FindPath(TreeNode<T> node, int sum, ref int currentSum, Stack<int> stack)
        {
            int data = Convert.ToInt32(node.Data);
            currentSum += data;
            stack.Push(data);
            // 如果是叶子节点,并且路径长度和等于输入整数,打印路径
            bool isLeafNode = node.LeftChild == null && node.RightChild == null;
            if(isLeafNode && currentSum == sum)
            {
                Console.WriteLine("Find Path : ");
                Stack<int>.Enumerator iter = stack.GetEnumerator();
                while (iter.MoveNext())
                {
                    Console.WriteLine(iter.Current);
                }
            }
            // 如果不是叶子节点,则遍历它的子节点
            if(node.LeftChild != null)
            {
                FindPath(node.LeftChild, sum, ref currentSum, stack);
            }
            if(node.RightChild != null)
            {
                FindPath(node.RightChild, sum, ref currentSum, stack);
            }
            // 在返回根节点之前,删除之前节点,currentSum减去相应的值
            currentSum -= data;
            stack.Pop();
        }

        public T Max
        {
            get
            {
                TreeNode<T> node = mRoot;
                while (node.RightChild != null)
                {
                    node = node.RightChild;
                }
                return node.Data;
            }
        }

        public T Min
        {
            get
            {
                if (mRoot != null)
                {
                    TreeNode<T> node = GetMinNode(mRoot);
                    return node.Data;
                }
                else
                {
                    return default(T);
                }
            }
        }

        public void DelMin()
        {
            mRoot = DelMin(mRoot);
        }

        private TreeNode<T> DelMin(TreeNode<T> node)
        {
            if (node.LeftChild == null)
            {
                return node.RightChild;
            }
            node.LeftChild = DelMin(node.LeftChild);
            return node;
        }

        public void Remove(T value)
        {
            mRoot = Delete(mRoot, value);
        }

        private TreeNode<T> Delete(TreeNode<T> node, T value)
        {
            if (node == null)
            {
                Console.WriteLine("没有找到要删除的节点: " + value);
                return null;
            }
            int comparer = mComparer.Compare(value, node.Data);
            if (comparer > 0)
            {
                node.RightChild = Delete(node.RightChild, value);
            }
            else if (comparer < 0)
            {
                node.LeftChild = Delete(node.LeftChild, value);
            }
            else
            {
                // 1.如果删除节点没有子节点,直接返回null
                // 2.如果只有一个子节点,返回其子节点代替删除节点即可
                if (node.LeftChild == null)
                {
                    return node.RightChild;
                }
                else if (node.RightChild == null)
                {
                    return node.LeftChild;
                }
                else
                {
                    // 3.当左右子节点都不为空时
                    // 找到其右子树中的最小节点,替换删除节点的位置
                    TreeNode<T> tempNode = node;
                    node = GetMinNode(tempNode.RightChild);
                    node.RightChild = DelMin(tempNode.RightChild);
                    node.LeftChild = tempNode.LeftChild;
                }
            }
            return node;
        }

        private TreeNode<T> GetMinNode(TreeNode<T> node)
        {
            while (node.LeftChild != null)
            {
                node = node.LeftChild;
            }
            return node;
        }

        // 递归方法实现体内再次调用方法本身的本质是多个方法的简写,递归一定要有出口
        public void ShowTree()
        {
            HierarchyOrder(mRoot);
        }

        // 前序遍历:首先访问根结点,然后遍历其左子树,最后遍历其右子树。
        private void PreOrder(TreeNode<T> node)
        {
            if (node == null)
            {
                return;
            }
            //打印节点数据
            Console.WriteLine(node.Data);
            PreOrder(node.LeftChild);
            PreOrder(node.RightChild);
        }

        // 对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。
        // 前序遍历
        private void PreOrder1(TreeNode<T> node)
        {
            Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
            TreeNode<T> curNode = node;
            s.Push(node);
            while (s.Count > 0)
            {
                Console.WriteLine(curNode.Data);
                if (curNode.RightChild != null)
                {
                    s.Push(curNode.RightChild);
                }
                if (curNode.LeftChild != null)
                {
                    curNode = curNode.LeftChild;
                }
                else
                {
                    //左子树访问完了,访问右子树
                    curNode = s.Pop();
                }
            }
        }

        // 中序遍历:首先遍历其左子树,然后访问根结点,最后遍历其右子树。
        private void InOrder(TreeNode<T> node)
        {
            if (node == null)
            {
                return;
            }
            InOrder(node.LeftChild);
            //打印节点数据
            Console.WriteLine(node.Data);
            InOrder(node.RightChild);
        }

        // 对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。
        // 中序遍历
        private void InOrder1(TreeNode<T> node)
        {
            Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
            TreeNode<T> curNode = node;
            while (curNode != null || s.Count > 0)
            {
                while (curNode != null)
                {
                    s.Push(curNode);
                    curNode = curNode.LeftChild;
                }
                if (s.Count > 0)
                {
                    curNode = s.Pop();
                    Console.WriteLine(curNode.Data);
                    curNode = curNode.RightChild;
                }
            }
        }

        // 后序遍历:首先遍历其左子树,然后遍历其右子树,最后访问根结点。
        private void PostOrder(TreeNode<T> node)
        {
            if (node == null)
            {
                return;
            }
            PostOrder(node.LeftChild);
            PostOrder(node.RightChild);
            //打印节点数据
            Console.WriteLine(node.Data);
        }

        // 后序遍历
        private void PostOrder1(TreeNode<T> node)
        {
            Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
            TreeNode<T> curNode = null;
            TreeNode<T> preNode = null;
            s.Push(node);
            while (s.Count > 0)
            {
                curNode = s.Peek();
                if ((curNode.LeftChild == null && curNode.RightChild == null) ||
                    (preNode != null && (preNode == curNode.LeftChild || preNode == curNode.RightChild)))
                {
                    //如果当前结点没有孩子结点或者孩子节点都已被访问过   
                    Console.WriteLine(curNode.Data);
                    s.Pop();
                    preNode = curNode;
                }
                else
                {
                    if (curNode.RightChild != null)
                    {
                        s.Push(curNode.RightChild);
                    }
                    if (curNode.LeftChild != null)
                    {
                        s.Push(curNode.LeftChild);
                    }
                }
            }
        }

        // 层次遍历
        private void HierarchyOrder(TreeNode<T> node)
        {
            Queue<TreeNode<T>> s = new Queue<TreeNode<T>>();
            s.Enqueue(node);
            while(s.Count > 0)
            {
                TreeNode<T> curNode = s.Dequeue();
                Console.WriteLine(curNode.Data);
                if(curNode.LeftChild != null)
                {
                    s.Enqueue(curNode.LeftChild);
                }
                if(curNode.RightChild != null)
                {
                    s.Enqueue(curNode.RightChild);
                }
            }
        }

    }

    public class TreeNode<T>
    {
        //数据
        public T Data { get; set; }

        //左孩子
        public TreeNode<T> LeftChild { get; set; }

        //右孩子
        public TreeNode<T> RightChild { get; set; }

        public TreeNode(T value, int count)
        {
            Data = value;
            LeftChild = null;
            RightChild = null;
        }
    }


}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值