服务器之家

服务器之家 > 正文

算法系列15天速成 第十一天 树操作(上)

时间:2020-07-27 16:58     来源/作者:编程技术网

先前我们讲的都是“线性结构”,他的特征就是“一个节点最多有一个”前驱“和一个”后继“。那么我们今天讲的树会是怎样的呢?

我们可以对”线性结构“改造一下,变为”一个节点最多有一个"前驱“和”多个后继“。哈哈,这就是我们今天说的”树“。

一: 树

      我们思维中的”树“就是一种枝繁叶茂的形象,那么数据结构中的”树“该是怎么样呢?对的,他是一种现实中倒立的树。

算法系列15天速成 第十一天 树操作(上)

1:术语

     其实树中有很多术语的,这个是我们学习树形结构必须掌握的。

     <1>  父节点,子节点,兄弟节点

                  这个就比较简单了,b和c的父节点就是a,反过来说就是b和c是a的子节点。b和c就是兄弟节点。

     <2>  结点的度

                 其实”度“就是”分支数“,比如a的分支数有两个“b和c",那么a的度为2。

     <3> 树的度

                看似比较莫名其妙吧,他和”结点的度“的区别就是,树的度讲究大局观,乃树中最大的结点度,其实也就是2。

     <4> 叶结点,分支结点

                叶结点就是既没有左孩子也没有右孩子结点,也就是结点度为0。分支节点也就是if的else的条件咯。

    <5> 结点的层数

               这个很简单,也就是树有几层。

   <6> 有序树,无序树

               有序树我们先前也用过,比如“堆”和“二叉排序树”,说明这种树是按照一定的规则进行排序的,else条件就是无序树。

   <7>  森林

               现实中,很多的树形成了森林,那在数据结构中,我们把上图的“a”节点砍掉,那么b,c子树合一起就是森林咯。

2: 树的表示

     树这个结构的表示其实有很多种,常用的也就是“括号”表示法。
     比如上面的树就可以表示为:(a(b(d),(e)),(c(f),(g)))

二: 二叉树

         在我们项目开发中,很多地方都会用到树,但是多叉树的处理还是比较纠结的,所以俺们本着“大事化小,小事化了“的原则

      把”多叉树“转化为”二叉树“,那么问题就简化了很多。

1: ”二叉树“和”树“有什么差异呢?

         第一点:  树的度没有限制,而“二叉树”最多只能有两个,不然也就不叫二叉树了,哈哈。
         第二点:树中的子树没有左右划分,很简单啊,找不到参照点,二叉树就有参照物咯。

2: 二叉树的类型

       二叉树中有两种比较完美的类型,“完全二叉树”和“满二叉树”。

          <1>  满二叉树    

                       除叶子节点外,所有节点的度都为2,文章开头处的树就是这里的“满二叉树”。

          <2>  完全二叉树

                      必须要满足两个条件就即可:  干掉最后一层,二叉树变为“满二叉树”。

   最后一层的叶节点必须是“从左到右”依次排开。

   我们干掉文章开头处的节点“f和”g",此时还是“完全二叉树”,但已经不是“满二叉树”了,你懂的。

3: 二叉树的性质

         二叉树中有5点性质非常重要,也是俺们必须要记住的。

     <1>  二叉树中,第i层的节点最多有2(i-1)个。

     <2>  深度为k的二叉树最多有2k-1个节点。

     <3>  二叉树中,叶子节点树为n1个,度为2的节点有n2个,那么n1=n2+1。

     <4>  具有n个结点的二叉树深度为(log2 n)+1层。

     <5>  n个结点的完全二叉树如何用顺序存储,对于其中的一个结点i,存在以下关系,

              2*i是结点i的父结点。

              i/2是结点i的左孩子。

              (i/2)+1是结点i的右孩子。

4: 二叉树的顺序存储

      同样的存储方式也有两种,“顺序存储”和“链式存储”。

       <1> 顺序存储

                 说实话,树的存储用顺序结构比较少,因为从性质定理中我们都可以看出只限定为“完全二叉树”,那么如果二叉树不是

              “完全二叉树”,那我们就麻烦了,必须将其转化为“完全二叉树”,将空的节点可以用“#”代替,图中也可看出,为了维护

              性质定理5的要求,我们牺牲了两个”资源“的空间。

算法系列15天速成 第十一天 树操作(上)

     <2> 链式存储

               上面也说了,顺序存储会造成资源的浪费,所以嘛,我们开发中用的比较多的还是“链式存储”,同样“链式存储”

            也非常的形象,非常的合理。

               一个结点存放着一个“左指针”和一个“右指针”,这就是二叉链表。

               如何方便的查找到该结点的父结点,可以采用三叉链表。

5: 常用操作

      一般也就是“添加结点“,“查找节点”,“计算深度”,“遍历结点”,“清空结点”

<1> 这里我们就用二叉链表来定义链式存储模型
 

 

复制代码 代码如下:


#region 二叉链表存储结构
    /// <summary>
/// 二叉链表存储结构
/// </summary>
/// <typeparam name="t"></typeparam>
    public class chaintree<t>
    {
        public t data;

 

        public chaintree<t> left;

        public chaintree<t> right;
    }
    #endregion

 

<2> 添加结点

  要添加结点,我们就要找到添加结点的父结点,并且根据指示插入到父结点中指定左结点或者右结点。

 

复制代码 代码如下:


#region 将指定节点插入到二叉树中
        /// <summary>
/// 将指定节点插入到二叉树中
/// </summary>
/// <typeparam name="t"></typeparam>
/// <param name="tree"></param>
/// <param name="node"></param>
/// <param name="direction">插入做左是右</param>
/// <returns></returns>
        public chaintree<t> bintreeaddnode<t>(chaintree<t> tree, chaintree<t> node, t data, direction direction)
        {
            if (tree == null)
                return null;

 

            if (tree.data.equals(data))
            {
                switch (direction)
                {
                    case direction.left:
                        if (tree.left != null)
                            throw new exception("树的左节点不为空,不能插入");
                        else
                            tree.left = node;

                        break;
                    case direction.right:
                        if (tree.right != null)
                            throw new exception("树的右节点不为空,不能插入");
                        else
                            tree.right = node;

                        break;
                }
            }

            bintreeaddnode(tree.left, node, data, direction);
            bintreeaddnode(tree.right, node, data, direction);

            return tree;
        }
        #endregion

 

<3>  查找节点 

                 二叉树中到处都散发着递归思想,很能锻炼一下我们对递归的认识,同样查找也是用到了递归思想。

 

复制代码 代码如下:


#region 在二叉树中查找指定的key
        /// <summary>
///在二叉树中查找指定的key
/// </summary>
/// <typeparam name="t"></typeparam>
/// <param name="tree"></param>
/// <param name="data"></param>
/// <returns></returns>
        public chaintree<t> bintreefind<t>(chaintree<t> tree, t data)
        {
            if (tree == null)
                return null;

 

            if (tree.data.equals(data))
                return tree;

            return bintreefind(tree, data);
        }
        #endregion

 

<4> 计算深度

          这个问题纠结了我二个多小时,原因在于没有深刻的体会到递归,其实主要思想就是递归左子树和右子树,然后得出较大的一个。

 

复制代码 代码如下:


#region 获取二叉树的深度
        /// <summary>
/// 获取二叉树的深度
/// </summary>
/// <typeparam name="t"></typeparam>
/// <param name="tree"></param>
/// <returns></returns>
        public int bintreelen<t>(chaintree<t> tree)
        {
            int leftlength;
            int rightlength;

 

            if (tree == null)
                return 0;

            //递归左子树的深度
            leftlength = bintreelen(tree.left);

            //递归右子书的深度
            rightlength = bintreelen(tree.right);

            if (leftlength > rightlength)
                return leftlength + 1;
            else
                return rightlength + 1;
        }
        #endregion

 

<5>  遍历结点

             二叉树中遍历节点的方法还是比较多的,有“先序”,“中序”,“后序”,“按层”,其实这些东西只可意会,不可言传,真的很难在口头

        上说清楚,需要反复的体会递归思想。

            先序:先访问根,然后递归访问左子树,最后递归右子树。(dlr模式)

            中序:先递归访问左子树,在访问根,最后递归右子树。(ldr模式)

            后序:先递归访问左子树,然后递归访问右子树,最后访问根。(lrd模式)

            按层:这个比较简单,从上到下,从左到右的遍历节点。

 

复制代码 代码如下:


#region 二叉树的先序遍历
        /// <summary>
/// 二叉树的先序遍历
/// </summary>
/// <typeparam name="t"></typeparam>
/// <param name="tree"></param>
        public void bintree_dlr<t>(chaintree<t> tree)
        {
            if (tree == null)
                return;

 

            //先输出根元素
            console.write(tree.data + "\t");

            //然后遍历左子树
            bintree_dlr(tree.left);

            //最后遍历右子树
            bintree_dlr(tree.right);
        }
        #endregion

        #region 二叉树的中序遍历
        /// <summary>
/// 二叉树的中序遍历
/// </summary>
/// <typeparam name="t"></typeparam>
/// <param name="tree"></param>
        public void bintree_ldr<t>(chaintree<t> tree)
        {
            if (tree == null)
                return;

            //优先遍历左子树
            bintree_ldr(tree.left);

            //然后输出节点
            console.write(tree.data + "\t");

            //最后遍历右子树
            bintree_ldr(tree.right);
        }
        #endregion

        #region 二叉树的后序遍历
        /// <summary>
/// 二叉树的后序遍历
/// </summary>
/// <typeparam name="t"></typeparam>
/// <param name="tree"></param>
        public void bintree_lrd<t>(chaintree<t> tree)
        {
            if (tree == null)
                return;

            //优先遍历左子树
            bintree_lrd(tree.left);

            //然后遍历右子树
            bintree_lrd(tree.right);

            //最后输出节点元素
            console.write(tree.data + "\t");
        }
        #endregion

        #region 二叉树的按层遍历
        /// <summary>
/// 二叉树的按层遍历
/// </summary>
/// <typeparam name="t"></typeparam>
/// <param name="tree"></param>
        public void bintree_level<t>(chaintree<t> tree)
        {
            if (tree == null)
                return;

            //申请保存空间
            chaintree<t>[] treelist = new chaintree<t>[length];

            int head = 0;
            int tail = 0;

            //存放数组
            treelist[tail] = tree;

            //循环链中计算tail位置
            tail = (tail + 1) % length;

            while (head != tail)
            {
                var tempnode = treelist[head];

                head = (head + 1) % length;

                //输出节点
                console.write(tempnode.data + "\t");

                //如果左子树不为空,则将左子树存于数组的tail位置
                if (tempnode.left != null)
                {
                    treelist[tail] = tempnode.left;

                    tail = (tail + 1) % length;
                }

                //如果右子树不为空,则将右子树存于数组的tail位置
                if (tempnode.right != null)
                {
                    treelist[tail] = tempnode.right;

                    tail = (tail + 1) % length;
                }
            }
        }
        #endregion

 

<6> 清空二叉树

           虽然c#里面有gc,但是我们能自己释放的就不麻烦gc了,同样清空二叉树节点,我们用到了递归,说实话,这次练习让我喜欢

       上的递归,虽然xxx的情况下,递归的不是很好,但是递归还是很强大的。

 

复制代码 代码如下:


#region 清空二叉树
        /// <summary>
/// 清空二叉树
/// </summary>
/// <typeparam name="t"></typeparam>
/// <param name="tree"></param>
        public void bintreeclear<t>(chaintree<t> tree)
        {
            //递的结束点,归的起始点
            if (tree == null)
                return;

 

            bintreeclear(tree.left);
            bintreeclear(tree.right);

            //在归的过程中,释放当前节点的数据空间
            tree = null;
        }
        #endregion

 

最后上一下总的代码

  1. using system; 
  2. using system.collections.generic; 
  3. using system.linq; 
  4. using system.text; 
  5.  
  6.  
  7.  
  8. namespace chaintree 
  9.     public class program 
  10.     { 
  11.         static void main(string[] args) 
  12.         { 
  13.             chaintreemanager manager = new chaintreemanager(); 
  14.  
  15.             //插入节点操作 
  16.             chaintree<string> tree = createroot(); 
  17.  
  18.             //插入节点数据 
  19.             addnode(tree); 
  20.  
  21.             //先序遍历 
  22.             console.writeline("\n先序结果为: \n"); 
  23.             manager.bintree_dlr(tree); 
  24.  
  25.             //中序遍历 
  26.             console.writeline("\n中序结果为: \n"); 
  27.             manager.bintree_ldr(tree); 
  28.  
  29.             //后序遍历 
  30.             console.writeline("\n后序结果为: \n"); 
  31.             manager.bintree_lrd(tree); 
  32.  
  33.             //层次遍历 
  34.             console.writeline("\n层次结果为: \n"); 
  35.             manager.length = 100; 
  36.             manager.bintree_level(tree); 
  37.  
  38.             console.writeline("\n树的深度为:" + manager.bintreelen(tree) + "\n"); 
  39.  
  40.             console.readline(); 
  41.  
  42.         } 
  43.  
  44.         #region 生成根节点 
  45.         /// <summary> 
  46. /// 生成根节点 
  47. /// </summary> 
  48. /// <returns></returns> 
  49.         static chaintree<string> createroot() 
  50.         { 
  51.             chaintree<string> tree = new chaintree<string>(); 
  52.  
  53.             console.writeline("请输入根节点,方便我们生成树\n"); 
  54.  
  55.             tree.data = console.readline(); 
  56.  
  57.             console.writeline("根节点生成已经生成\n"); 
  58.  
  59.             return tree; 
  60.         } 
  61.         #endregion 
  62.  
  63.         #region 插入节点操作 
  64.         /// <summary> 
  65. /// 插入节点操作 
  66. /// </summary> 
  67. /// <param name="tree"></param> 
  68.         static chaintree<string> addnode(chaintree<string> tree) 
  69.         { 
  70.             chaintreemanager mananger = new chaintreemanager(); 
  71.  
  72.             while (true
  73.             { 
  74.                 chaintree<string> node = new chaintree<string>(); 
  75.  
  76.                 console.writeline("请输入要插入节点的数据:\n"); 
  77.  
  78.                 node.data = console.readline(); 
  79.  
  80.                 console.writeline("请输入要查找的父节点数据:\n"); 
  81.  
  82.                 var parentdata = console.readline(); 
  83.  
  84.                 if (tree == null
  85.                 { 
  86.                     console.writeline("未找到您输入的父节点,请重新输入。"); 
  87.                     continue
  88.                 } 
  89.  
  90.                 console.writeline("请确定要插入到父节点的:1 左侧,2 右侧"); 
  91.  
  92.                 direction direction = (direction)enum.parse(typeof(direction), console.readline()); 
  93.  
  94.                 tree = mananger.bintreeaddnode(tree, node, parentdata, direction); 
  95.  
  96.                 console.writeline("插入成功,是否继续?  1 继续, 2 退出"); 
  97.  
  98.                 if (int.parse(console.readline()) == 1) 
  99.                     continue
  100.                 else 
  101.                     break
  102.             } 
  103.  
  104.             return tree; 
  105.         } 
  106.         #endregion 
  107.     } 
  108.  
  109.     #region 插入左节点或者右节点 
  110.     /// <summary> 
  111. /// 插入左节点或者右节点 
  112. /// </summary> 
  113.     public enum direction { left = 1, right = 2 } 
  114.     #endregion 
  115.  
  116.     #region 二叉链表存储结构 
  117.     /// <summary> 
  118. /// 二叉链表存储结构 
  119. /// </summary> 
  120. /// <typeparam name="t"></typeparam> 
  121.     public class chaintree<t> 
  122.     { 
  123.         public t data; 
  124.  
  125.         public chaintree<t> left; 
  126.  
  127.         public chaintree<t> right; 
  128.     } 
  129.     #endregion 
  130.  
  131.     /// <summary> 
  132. /// 二叉树的操作帮助类 
  133. /// </summary> 
  134.     public class chaintreemanager 
  135.     { 
  136.         #region 按层遍历的length空间存储 
  137.         /// <summary> 
  138. /// 按层遍历的length空间存储 
  139. /// </summary> 
  140.         public int length { get; set; } 
  141.         #endregion 
  142.  
  143.         #region 将指定节点插入到二叉树中 
  144.         /// <summary> 
  145. /// 将指定节点插入到二叉树中 
  146. /// </summary> 
  147. /// <typeparam name="t"></typeparam> 
  148. /// <param name="tree"></param> 
  149. /// <param name="node"></param> 
  150. /// <param name="direction">插入做左是右</param> 
  151. /// <returns></returns> 
  152.         public chaintree<t> bintreeaddnode<t>(chaintree<t> tree, chaintree<t> node, t data, direction direction) 
  153.         { 
  154.             if (tree == null
  155.                 return null
  156.  
  157.             if (tree.data.equals(data)) 
  158.             { 
  159.                 switch (direction) 
  160.                 { 
  161.                     case direction.left: 
  162.                         if (tree.left != null
  163.                             throw new exception("树的左节点不为空,不能插入"); 
  164.                         else 
  165.                             tree.left = node; 
  166.  
  167.                         break
  168.                     case direction.right: 
  169.                         if (tree.right != null
  170.                             throw new exception("树的右节点不为空,不能插入"); 
  171.                         else 
  172.                             tree.right = node; 
  173.  
  174.                         break
  175.                 } 
  176.             } 
  177.  
  178.             bintreeaddnode(tree.left, node, data, direction); 
  179.             bintreeaddnode(tree.right, node, data, direction); 
  180.  
  181.             return tree; 
  182.         } 
  183.         #endregion 
  184.  
  185.         #region 获取二叉树指定孩子的状态 
  186.         /// <summary> 
  187. /// 获取二叉树指定孩子的状态 
  188. /// </summary> 
  189. /// <typeparam name="t"></typeparam> 
  190. /// <param name="tree"></param> 
  191. /// <param name="direction"></param> 
  192. /// <returns></returns> 
  193.         public chaintree<t> bintreechild<t>(chaintree<t> tree, direction direction) 
  194.         { 
  195.             chaintree<t> childnode = null
  196.  
  197.             if (tree == null
  198.                 throw new exception("二叉树为空"); 
  199.  
  200.             switch (direction) 
  201.             { 
  202.                 case direction.left: 
  203.                     childnode = tree.left; 
  204.                     break
  205.                 case direction.right: 
  206.                     childnode = tree.right; 
  207.                     break
  208.             } 
  209.  
  210.             return childnode; 
  211.         } 
  212.  
  213.         #endregion 
  214.  
  215.         #region 获取二叉树的深度 
  216.         /// <summary> 
  217. /// 获取二叉树的深度 
  218. /// </summary> 
  219. /// <typeparam name="t"></typeparam> 
  220. /// <param name="tree"></param> 
  221. /// <returns></returns> 
  222.         public int bintreelen<t>(chaintree<t> tree) 
  223.         { 
  224.             int leftlength; 
  225.             int rightlength; 
  226.  
  227.             if (tree == null
  228.                 return 0; 
  229.  
  230.             //递归左子树的深度 
  231.             leftlength = bintreelen(tree.left); 
  232.  
  233.             //递归右子书的深度 
  234.             rightlength = bintreelen(tree.right); 
  235.  
  236.             if (leftlength > rightlength) 
  237.                 return leftlength + 1; 
  238.             else 
  239.                 return rightlength + 1; 
  240.         } 
  241.         #endregion 
  242.  
  243.         #region 判断二叉树是否为空 
  244.         /// <summary> 
  245. /// 判断二叉树是否为空 
  246. /// </summary> 
  247. /// <typeparam name="t"></typeparam> 
  248. /// <param name="tree"></param> 
  249. /// <returns></returns> 
  250.         public bool bintreeisempty<t>(chaintree<t> tree) 
  251.         { 
  252.             return tree == null ? true : false
  253.         } 
  254.         #endregion 
  255.  
  256.         #region 在二叉树中查找指定的key 
  257.         /// <summary> 
  258. ///在二叉树中查找指定的key 
  259. /// </summary> 
  260. /// <typeparam name="t"></typeparam> 
  261. /// <param name="tree"></param> 
  262. /// <param name="data"></param> 
  263. /// <returns></returns> 
  264.         public chaintree<t> bintreefind<t>(chaintree<t> tree, t data) 
  265.         { 
  266.             if (tree == null
  267.                 return null
  268.  
  269.             if (tree.data.equals(data)) 
  270.                 return tree; 
  271.  
  272.             return bintreefind(tree, data); 
  273.         } 
  274.         #endregion 
  275.  
  276.         #region 清空二叉树 
  277.         /// <summary> 
  278. /// 清空二叉树 
  279. /// </summary> 
  280. /// <typeparam name="t"></typeparam> 
  281. /// <param name="tree"></param> 
  282.         public void bintreeclear<t>(chaintree<t> tree) 
  283.         { 
  284.             //递的结束点,归的起始点 
  285.             if (tree == null
  286.                 return
  287.  
  288.             bintreeclear(tree.left); 
  289.             bintreeclear(tree.right); 
  290.  
  291.             //在归的过程中,释放当前节点的数据空间 
  292.             tree = null
  293.         } 
  294.         #endregion 
  295.  
  296.         #region 二叉树的先序遍历 
  297.         /// <summary> 
  298. /// 二叉树的先序遍历 
  299. /// </summary> 
  300. /// <typeparam name="t"></typeparam> 
  301. /// <param name="tree"></param> 
  302.         public void bintree_dlr<t>(chaintree<t> tree) 
  303.         { 
  304.             if (tree == null
  305.                 return
  306.  
  307.             //先输出根元素 
  308.             console.write(tree.data + "\t"); 
  309.  
  310.             //然后遍历左子树 
  311.             bintree_dlr(tree.left); 
  312.  
  313.             //最后遍历右子树 
  314.             bintree_dlr(tree.right); 
  315.         } 
  316.         #endregion 
  317.  
  318.         #region 二叉树的中序遍历 
  319.         /// <summary> 
  320. /// 二叉树的中序遍历 
  321. /// </summary> 
  322. /// <typeparam name="t"></typeparam> 
  323. /// <param name="tree"></param> 
  324.         public void bintree_ldr<t>(chaintree<t> tree) 
  325.         { 
  326.             if (tree == null
  327.                 return
  328.  
  329.             //优先遍历左子树 
  330.             bintree_ldr(tree.left); 
  331.  
  332.             //然后输出节点 
  333.             console.write(tree.data + "\t"); 
  334.  
  335.             //最后遍历右子树 
  336.             bintree_ldr(tree.right); 
  337.         } 
  338.         #endregion 
  339.  
  340.         #region 二叉树的后序遍历 
  341.         /// <summary> 
  342. /// 二叉树的后序遍历 
  343. /// </summary> 
  344. /// <typeparam name="t"></typeparam> 
  345. /// <param name="tree"></param> 
  346.         public void bintree_lrd<t>(chaintree<t> tree) 
  347.         { 
  348.             if (tree == null
  349.                 return
  350.  
  351.             //优先遍历左子树 
  352.             bintree_lrd(tree.left); 
  353.  
  354.             //然后遍历右子树 
  355.             bintree_lrd(tree.right); 
  356.  
  357.             //最后输出节点元素 
  358.             console.write(tree.data + "\t"); 
  359.         } 
  360.         #endregion 
  361.  
  362.         #region 二叉树的按层遍历 
  363.         /// <summary> 
  364. /// 二叉树的按层遍历 
  365. /// </summary> 
  366. /// <typeparam name="t"></typeparam> 
  367. /// <param name="tree"></param> 
  368.         public void bintree_level<t>(chaintree<t> tree) 
  369.         { 
  370.             if (tree == null
  371.                 return
  372.  
  373.             //申请保存空间 
  374.             chaintree<t>[] treelist = new chaintree<t>[length]; 
  375.  
  376.             int head = 0; 
  377.             int tail = 0; 
  378.  
  379.             //存放数组 
  380.             treelist[tail] = tree; 
  381.  
  382.             //循环链中计算tail位置 
  383.             tail = (tail + 1) % length; 
  384.  
  385.             while (head != tail) 
  386.             { 
  387.                 var tempnode = treelist[head]; 
  388.  
  389.                 head = (head + 1) % length; 
  390.  
  391.                 //输出节点 
  392.                 console.write(tempnode.data + "\t"); 
  393.  
  394.                 //如果左子树不为空,则将左子树存于数组的tail位置 
  395.                 if (tempnode.left != null
  396.                 { 
  397.                     treelist[tail] = tempnode.left; 
  398.  
  399.                     tail = (tail + 1) % length; 
  400.                 } 
  401.  
  402.                 //如果右子树不为空,则将右子树存于数组的tail位置 
  403.                 if (tempnode.right != null
  404.                 { 
  405.                     treelist[tail] = tempnode.right; 
  406.  
  407.                     tail = (tail + 1) % length; 
  408.                 } 
  409.             } 
  410.         } 
  411.         #endregion 
  412.  
  413.     } 

我们把文章开头的“二叉树”的节点输入到我们的结构中,看看遍历效果咋样。
 

算法系列15天速成 第十一天 树操作(上)

标签:

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享 2020-04-07
Intellij idea2020永久破解,亲测可用!!!
Intellij idea2020永久破解,亲测可用!!! 2020-05-20
男生常说24816是什么意思?女生说13579是什么意思?
男生常说24816是什么意思?女生说13579是什么意思? 2019-09-17
沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意
沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意 2019-07-07
返回顶部