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

16 篇文章 0 订阅

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


转自:http://blog.csdn.net/m13666368773/article/details/7530304

最近项目赶的紧,歇了一个星期没写博客了,趁周末继续写这个系列。

 

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

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

 

一: 树

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

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个结点的二叉树深度为(LogN)+1层。

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

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

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

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

 

4: 二叉树的顺序存储

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

       <1> 顺序存储

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

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

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

     <2> 链式存储

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

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

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

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

 

5: 常用操作

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

   

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

复制代码
[csharp]  view plain  copy
  1. #region 二叉链表存储结构  
  2.      /// <summary>  
  3.  /// 二叉链表存储结构  
  4.  /// </summary>  
  5.  /// <typeparam name="T"></typeparam>  
  6.      public class ChainTree<T>  
  7.      {  
  8.          public T data;  
  9.    
  10.          public ChainTree<T> left;  
  11.    
  12.          public ChainTree<T> right;   
  13.      }  
  14.      #endregion  

 

<2> 添加结点

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

复制代码
[csharp]  view plain  copy
  1. #region 将指定节点插入到二叉树中  
  2.          /// <summary>  
  3.  /// 将指定节点插入到二叉树中  
  4.  /// </summary>  
  5.  /// <typeparam name="T"></typeparam>  
  6.  /// <param name="tree"></param>  
  7.  /// <param name="node"></param>  
  8.  /// <param name="direction">插入做左是右</param>  
  9.  /// <returns></returns>  
  10.          public ChainTree<T> BinTreeAddNode<T>(ChainTree<T> tree, ChainTree<T> node, T data, Direction direction)  
  11.          {  
  12.              if (tree == null)  
  13.                  return null;  
  14.    
  15.              if (tree.data.Equals(data))  
  16.              {  
  17.                  switch (direction)  
  18.                  {  
  19.                      case Direction.Left:  
  20.                          if (tree.left != null)  
  21.                              throw new Exception("树的左节点不为空,不能插入");  
  22.                          else  
  23.                              tree.left = node;  
  24.    
  25.                          break;  
  26.                      case Direction.Right:  
  27.                          if (tree.right != null)  
  28.                              throw new Exception("树的右节点不为空,不能插入");  
  29.                          else  
  30.                              tree.right = node;  
  31.    
  32.                          break;  
  33.                  }  
  34.              }  
  35.    
  36.              BinTreeAddNode(tree.left, node, data, direction);  
  37.              BinTreeAddNode(tree.right, node, data, direction);  
  38.    
  39.              return tree;  
  40.          }  
  41.          #endregion  

     

<3>  查找节点  

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

复制代码
[csharp]  view plain  copy
  1. #region 在二叉树中查找指定的key  
  2.          /// <summary>  
  3.  ///在二叉树中查找指定的key  
  4.  /// </summary>  
  5.  /// <typeparam name="T"></typeparam>  
  6.  /// <param name="tree"></param>  
  7.  /// <param name="data"></param>  
  8.  /// <returns></returns>  
  9.          public ChainTree<T> BinTreeFind<T>(ChainTree<T> tree, T data)  
  10.          {  
  11.              if (tree == null)  
  12.                  return null;  
  13.    
  14.              if (tree.data.Equals(data))  
  15.                  return tree;  
  16.    
  17.              return BinTreeFind(tree, data);  
  18.          }  
  19.          #endregion  

     

<4> 计算深度

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

复制代码
[csharp]  view plain  copy
  1. #region 获取二叉树的深度  
  2.          /// <summary>  
  3.  /// 获取二叉树的深度  
  4.  /// </summary>  
  5.  /// <typeparam name="T"></typeparam>  
  6.  /// <param name="tree"></param>  
  7.  /// <returns></returns>  
  8.          public int BinTreeLen<T>(ChainTree<T> tree)  
  9.          {  
  10.              int leftLength;  
  11.              int rightLength;  
  12.    
  13.              if (tree == null)  
  14.                  return 0;  
  15.    
  16.              //递归左子树的深度  
  17.              leftLength = BinTreeLen(tree.left);  
  18.    
  19.              //递归右子书的深度  
  20.              rightLength = BinTreeLen(tree.right);  
  21.    
  22.              if (leftLength > rightLength)  
  23.                  return leftLength + 1;  
  24.              else  
  25.                  return rightLength + 1;  
  26.          }  
  27.          #endregion  

<5>  遍历结点

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

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

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

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

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

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

复制代码
[csharp]  view plain  copy
  1. #region 二叉树的先序遍历  
  2.          /// <summary>  
  3.  /// 二叉树的先序遍历  
  4.  /// </summary>  
  5.  /// <typeparam name="T"></typeparam>  
  6.  /// <param name="tree"></param>  
  7.          public void BinTree_DLR<T>(ChainTree<T> tree)  
  8.          {  
  9.              if (tree == null)  
  10.                  return;  
  11.    
  12.              //先输出根元素  
  13.              Console.Write(tree.data + "\t");  
  14.    
  15.              //然后遍历左子树  
  16.              BinTree_DLR(tree.left);  
  17.    
  18.              //最后遍历右子树  
  19.              BinTree_DLR(tree.right);  
  20.          }  
  21.          #endregion  
  22.   
  23.          #region 二叉树的中序遍历  
  24.          /// <summary>  
  25.  /// 二叉树的中序遍历  
  26.  /// </summary>  
  27.  /// <typeparam name="T"></typeparam>  
  28.  /// <param name="tree"></param>  
  29.          public void BinTree_LDR<T>(ChainTree<T> tree)  
  30.          {  
  31.              if (tree == null)  
  32.                  return;  
  33.    
  34.              //优先遍历左子树  
  35.              BinTree_LDR(tree.left);  
  36.    
  37.              //然后输出节点  
  38.              Console.Write(tree.data + "\t");  
  39.    
  40.              //最后遍历右子树  
  41.              BinTree_LDR(tree.right);  
  42.          }  
  43.          #endregion  
  44.   
  45.          #region 二叉树的后序遍历  
  46.          /// <summary>  
  47.  /// 二叉树的后序遍历  
  48.  /// </summary>  
  49.  /// <typeparam name="T"></typeparam>  
  50.  /// <param name="tree"></param>  
  51.          public void BinTree_LRD<T>(ChainTree<T> tree)  
  52.          {  
  53.              if (tree == null)  
  54.                  return;  
  55.    
  56.              //优先遍历左子树  
  57.              BinTree_LRD(tree.left);  
  58.    
  59.              //然后遍历右子树  
  60.              BinTree_LRD(tree.right);  
  61.    
  62.              //最后输出节点元素  
  63.              Console.Write(tree.data + "\t");  
  64.          }  
  65.          #endregion  
  66.   
  67.          #region 二叉树的按层遍历  
  68.          /// <summary>  
  69.  /// 二叉树的按层遍历  
  70.  /// </summary>  
  71.  /// <typeparam name="T"></typeparam>  
  72.  /// <param name="tree"></param>  
  73.          public void BinTree_Level<T>(ChainTree<T> tree)  
  74.          {  
  75.              if (tree == null)  
  76.                  return;  
  77.    
  78.              //申请保存空间  
  79.              ChainTree<T>[] treeList = new ChainTree<T>[Length];  
  80.    
  81.              int head = 0;  
  82.              int tail = 0;  
  83.    
  84.              //存放数组  
  85.              treeList[tail] = tree;  
  86.    
  87.              //循环链中计算tail位置  
  88.              tail = (tail + 1) % Length;  
  89.    
  90.              while (head != tail)  
  91.              {  
  92.                  var tempNode = treeList[head];  
  93.    
  94.                  head = (head + 1) % Length;  
  95.    
  96.                  //输出节点  
  97.                  Console.Write(tempNode.data + "\t");  
  98.    
  99.                  //如果左子树不为空,则将左子树存于数组的tail位置  
  100.                  if (tempNode.left != null)  
  101.                  {  
  102.                      treeList[tail] = tempNode.left;  
  103.    
  104.                      tail = (tail + 1) % Length;  
  105.                  }  
  106.    
  107.                  //如果右子树不为空,则将右子树存于数组的tail位置  
  108.                  if (tempNode.right != null)  
  109.                  {  
  110.                      treeList[tail] = tempNode.right;  
  111.    
  112.                      tail = (tail + 1) % Length;  
  113.                  }  
  114.              }  
  115.          }  
  116.          #endregion  

 

<6> 清空二叉树

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

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

复制代码
[csharp]  view plain  copy
  1. #region 清空二叉树  
  2.          /// <summary>  
  3.  /// 清空二叉树  
  4.  /// </summary>  
  5.  /// <typeparam name="T"></typeparam>  
  6.  /// <param name="tree"></param>  
  7.          public void BinTreeClear<T>(ChainTree<T> tree)  
  8.          {  
  9.              //递的结束点,归的起始点  
  10.              if (tree == null)  
  11.                  return;  
  12.    
  13.              BinTreeClear(tree.left);  
  14.              BinTreeClear(tree.right);  
  15.    
  16.              //在归的过程中,释放当前节点的数据空间  
  17.              tree = null;  
  18.          }  
  19.          #endregion  

最后上一下总的代码
[csharp]  view plain  copy
  1. View Code   
  2.  using System;  
  3.  using System.Collections.Generic;  
  4.  using System.Linq;  
  5.  using System.Text;  
  6.    
  7.  namespace ChainTree  
  8.  {  
  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 { getset; }  
  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.      }  
  414.  }  

  

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

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值