zoukankan      html  css  js  c++  java
  • C#数据结构-二叉树-链式存储结构

    对比上一篇文章“顺序存储二叉树”,链式存储二叉树的优点是节省空间。

    二叉树的性质:

    1、在二叉树的第i层上至多有2i-1个节点(i>=1)。

    2、深度为k的二叉树至多有2k-1个节点(k>=1)。

    3、对任何一棵二叉树T,如果其终结点数为n0,度为2的节点数为n2,则n0=n2+1。

    4、具有n个节点的完全二叉树的深度为log2n+1。

    5、对于一棵有n个节点的完全二叉树的节点按层序编号,若完全二叉树中的某节点编号为i,则若有左孩子编号为2i,若有右孩子编号为2i+1,母亲节点为i/2。

    在此记录下链式二叉树的实现方式 :

    /// <summary>
        /// 树节点
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class TreeNode<T>
        {
            /// <summary>
            /// 节点数据
            /// </summary>
            public T data { get; set; }
            /// <summary>
            /// 左节点
            /// </summary>
            public TreeNode<T> leftChild { get; set; }
            /// <summary>
            /// 右节点
            /// </summary>
            public TreeNode<T> rightChild { get; set; }
    
            public TreeNode()
            {
                data = default(T);
                leftChild = null;
                rightChild = null;
            }
    
            public TreeNode(T item)
            {
                data = item;
                leftChild = null;
                rightChild = null;
            }
        }
        /// <summary>
        /// 二叉树 链表存储结构
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class LinkStorageBinaryTree<T>
        {
            /// <summary>
            /// 树根节
            /// </summary>
            private TreeNode<T> head { get; set; }
    
            public LinkStorageBinaryTree()
            {
                head = null;
            }
    
            public LinkStorageBinaryTree(T val)
            {
                head = new TreeNode<T>(val);
            }
            /// <summary>
            /// 获取左节点
            /// </summary>
            /// <param name="treeNode"></param>
            /// <returns></returns>
            public TreeNode<T> GetLeftNode(TreeNode<T> treeNode)
            {
                if (treeNode == null)
                    return null;
                return treeNode.leftChild;
            }
            /// <summary>
            /// 获取右节点
            /// </summary>
            /// <param name="treeNode"></param>
            /// <returns></returns>
            public TreeNode<T> GetRightNode(TreeNode<T> treeNode)
            {
                if (treeNode == null)
                    return null;
                return treeNode.rightChild;
            }
            /// <summary>
            /// 获取根节点
            /// </summary>
            /// <returns></returns>
            public TreeNode<T> GetRoot()
            {
                return head;
            }
            /// <summary>
            /// 插入左节点
            /// </summary>
            /// <param name="val"></param>
            /// <param name="node"></param>
            /// <returns></returns>
            public TreeNode<T> AddLeftNode(T val,TreeNode<T> node)
            {
                if (node == null)
                    throw new ArgumentNullException("参数错误");
                TreeNode<T> treeNode = new TreeNode<T>(val);
                TreeNode<T> childNode = node.leftChild;
                treeNode.leftChild = childNode;
                node.leftChild = treeNode;
                return treeNode;
            }
    
            /// <summary>
            /// 插入右节点
            /// </summary>
            /// <param name="val"></param>
            /// <param name="node"></param>
            /// <returns></returns>
            public TreeNode<T> AddRightNode(T val, TreeNode<T> node)
            {
                if (node == null)
                    throw new ArgumentNullException("参数错误");
                TreeNode<T> treeNode = new TreeNode<T>(val);
                TreeNode<T> childNode = node.rightChild;
                treeNode.rightChild = childNode;
                node.rightChild = treeNode;
                return treeNode;
            }
            /// <summary>
            /// 删除当前节点的 左节点
            /// </summary>
            /// <param name="node"></param>
            /// <returns></returns>
            public TreeNode<T> DeleteLeftNode(TreeNode<T> node)
            {
                if (node == null || node.leftChild == null)
                    throw new ArgumentNullException("参数错误");
                TreeNode<T> leftChild = node.leftChild;
                node.leftChild = null;
                return leftChild;
            }
    
            /// <summary>
            /// 删除当前节点的 右节点
            /// </summary>
            /// <param name="node"></param>
            /// <returns></returns>
            public TreeNode<T> DeleteRightNode(TreeNode<T> node)
            {
                if (node == null || node.leftChild == null)
                    throw new ArgumentNullException("参数错误");
                TreeNode<T> rightChild = node.rightChild;
                node.rightChild = null;
                return rightChild;
            }
    
            /// <summary>
            /// 先序遍历
            /// </summary>
            /// <param name="index"></param>
            public void PreorderTraversal(TreeNode<T> node)
            {
                //递归的终止条件
                if (head == null)
                {
                    Console.WriteLine("当前树为空");
                    return;
                }
                if (node != null)
                {
                    Console.Write(node.data+ " ");
                    PreorderTraversal(node.leftChild);
                    PreorderTraversal(node.rightChild);
                }
            }
    
            /// <summary>
            /// 中序遍历
            /// </summary>
            /// <param name="index"></param>
            public void MiddlePrefaceTraversal(TreeNode<T> node)
            {
                //递归的终止条件
                if (head == null)
                {
                    Console.WriteLine("当前树为空");
                    return;
                }
                if (node != null)
                {
                    MiddlePrefaceTraversal(node.leftChild);
    
                    Console.Write(node.data + " ");
    
                    MiddlePrefaceTraversal(node.rightChild);
                }
            }
    
            /// <summary>
            /// 后序遍历
            /// </summary>
            /// <param name="index"></param>
            public void AfterwordTraversal(TreeNode<T> node)
            {
                //递归的终止条件
                if (head == null)
                {
                    Console.WriteLine("当前树为空");
                    return;
                }
                if (node != null)
                {
                    AfterwordTraversal(node.leftChild);
                    AfterwordTraversal(node.rightChild);
                    Console.Write(node.data + " ");
                }
            }
    
    
            public void LevelTraversal()
            {
                if (head == null)
                    return;
                //使用队列先入先出
                Queue<TreeNode<T>> queue = new Queue<TreeNode<T>>();
                queue.Enqueue(head);
    
                while (queue.Any())
                {
                    TreeNode<T> item = queue.Dequeue();
                    Console.Write(item.data +" ");
                    if (item.leftChild != null)
                        queue.Enqueue(item.leftChild);
                    if (item.rightChild != null)
                        queue.Enqueue(item.rightChild);
                }
            }
            /// <summary>
            /// 校验节点是否是叶子节点
            /// </summary>
            /// <param name="node"></param>
            /// <returns></returns>
            public bool ValidLeafNode(TreeNode<T> node)
            {
                if (node == null)
                    throw new ArgumentNullException("参数错误");
                if (node.leftChild != null && node.rightChild != null)
                {
                    Console.WriteLine($"节点 {node.data} 不是叶子节点");
                    return false;
                }
                Console.WriteLine($"节点 {node.data} 是叶子节点");
                return true;
            }
        }

    遍历方式在顺序存储一文中已经用图表示过,在此不做重复说明。

    现在测试下:

    LinkStorageBinaryTree<string> linkStorageBinary = new LinkStorageBinaryTree<string>("A");
    TreeNode<string> tree1 = linkStorageBinary.AddLeftNode("B", linkStorageBinary.GetRoot());
    TreeNode<string> tree2 = linkStorageBinary.AddRightNode("C", linkStorageBinary.GetRoot());
    TreeNode<string> tree3 =linkStorageBinary.AddLeftNode("D", tree1);
    linkStorageBinary.AddRightNode("E",tree1);
    linkStorageBinary.AddLeftNode("F", tree2);
    linkStorageBinary.AddRightNode("G", tree2);
    
    //先序遍历
    Console.Write("先序遍历:");
    linkStorageBinary.PreorderTraversal(linkStorageBinary.GetRoot());
    Console.WriteLine();
    
    //中序遍历
    Console.Write("中序遍历:");
    linkStorageBinary.MiddlePrefaceTraversal(linkStorageBinary.GetRoot());
    Console.WriteLine();
    
    //中序遍历
    Console.Write("后序遍历:");
    linkStorageBinary.AfterwordTraversal(linkStorageBinary.GetRoot());
    Console.WriteLine();
    
    //层次遍历
    Console.Write("层次遍历:");
    linkStorageBinary.LevelTraversal();
    
    linkStorageBinary.ValidLeafNode(tree1);
    linkStorageBinary.ValidLeafNode(tree3);
    Console.ReadKey();

    输出:

    先序遍历:A B D E C F G
    中序遍历:D B E A F C G
    后序遍历:D E B F G C A
    层次遍历:A B C D E F G 节点 B 不是叶子节点
    节点 D 是叶子节点

  • 相关阅读:
    Mysql常用命令行大全(转)
    python 列表返回重复数据的下标
    啊哈算法, 水管工游戏
    python 实现结构体
    最长子回文字符串(Manacher’s Algorithm)
    一张图说明容器和镜像和仓库的关系
    nginx命令大全
    Django(request和response)
    python django + js 使用ajax进行文件上传并获取上传进度案例
    详解django三种文件下载方式
  • 原文地址:https://www.cnblogs.com/xtt321/p/14093041.html
Copyright © 2011-2022 走看看