二叉树绘制器BinaryTreeDrawer实现

我们可能需要将一个二叉树以图形化的方式显示出来,我实现了一个二叉树绘制器BinaryTreeDrawer,用于绘制前文实现的二叉树。

先看看这个绘制器的外貌:

public interface IBinaryTreeDrawer
 {
  void Initialize(DrawerParas paras) ;
  void ResetGraphic(Graphics g) ;     //在设备发生变化或尺寸改变时需重设设备句柄
  void DrawBinaryTree(ISorttedBinaryTree tree ,int offsetLeft ,int offsetHigh) ; //offset用于滚动
  void Zoom(double coeff) ;
  Size GetCanvasSize(int binaryTreeDepth ,int radius) ; //根据树的深度和结点半径获得画布大小

  int Radius{ get ;} //节点半径
 }
 

 //绘制器参数
 public class DrawerParas
 {
  public Graphics Graphic = null; //在何种设备上绘制
  public Color GraphicBackColor = Color.Gainsboro;
  public int Radius = 10 ; //节点圆的半径
  public Pen PenNode = new Pen(Color.Black ,1) ;
  public Pen PenLine = new Pen(Color.Black ,1) ;
  public SolidBrush BrushNode = new SolidBrush(Color.Pink);  
  public Font  FontText =  new Font("Arial", 9);
  public SolidBrush BrushText = new SolidBrush(Color.Black);
 }

接口没什么说的,实现如下:

public class BinaryTreeDrawer :IBinaryTreeDrawer
 {
  private DrawerParas drawParas = null ;
  private ISorttedBinaryTree curTree = null ;
  private int offsetX = 0 ;
  private int offsetY = 0 ;

  public BinaryTreeDrawer()
  {   
  }

  #region IBinaryDrawer 成员

  public void Initialize(DrawerParas paras)
  {
   this.drawParas = paras ;
  }

  public void ResetGraphic(Graphics g)
  {
   if(this.drawParas != null)
   {
    this.drawParas.Graphic = g ;
   }
  }

  public Size GetCanvasSize(int binaryTreeDepth ,int radius)
  {
   int width = radius * (int)(Math.Pow(2 ,binaryTreeDepth-1)) ;
   int heigh = radius * binaryTreeDepth ;

   return new Size(width ,heigh);
  }

  public void Zoom(double coeff)
  {
   this.drawParas.Radius = (int)(this.drawParas.Radius * coeff );
   if(this.curTree != null)
   {
    this.DrawBinaryTree(this.curTree ,this.offsetX ,this.offsetY) ;
   }
  }

  public void DrawBinaryTree(ISorttedBinaryTree tree ,int offsetLeft ,int offsetHigh)
  {
   if((this.drawParas == null) || (tree == null) ||(tree.Count == 0))
   {
    return ;
   }

   this.curTree = tree ;
   this.offsetX = offsetLeft ;
   this.offsetY = offsetHigh ;

   try
   {    
    this.drawParas.Graphic.Clear(this.drawParas.GraphicBackColor) ;    

    Point[][] position = this.GetNodePosition(tree.Depth) ;

    Node root = tree.Root ;

    this.DrawTree(root ,0 ,0 ,this.drawParas.Graphic ,position ,offsetLeft ,offsetHigh) ;      
   }
   catch(Exception ee)
   {
    ee =ee ;
   }
  }

  public int Radius
  {
   get
   {
    if(this.drawParas == null)
    {
     return 0 ;
    }

    return this.drawParas.Radius ;
   }
  }

  #endregion

  #region private
  #region GetNodePosition
  private Point[][] GetNodePosition(int depth)
  {   
   Point[][] position = new Point[depth][] ;

   for(int i=0 ;i<depth ;i++)
   {
    position[i] = new Point[(int)Math.Pow(2 ,i)] ;
   }

   //初始化最下一层
   for(int j=0 ;j<Math.Pow(2 ,depth-1) ;j++ )
   {
    position[depth-1][j].X =  2*j ;//(int)(-( 2*(Math.Pow(2 ,depth-1)) -1 )/2) + 2*j ;
    position[depth-1][j].Y = 2 * (depth) ;
   }


   //初始化其它层
   if(depth >=2)
   {   
    for(int i=depth-2 ;i>=0 ;i--)
    {
     for(int j=0 ;j<Math.Pow(2 ,i) ;j++ )
     {
      position[i][j].X = (position[i+1][2*j].X + position[i+1][2*j + 1].X)/2 ;
      position[i][j].Y = 2 * (i+1) ;
     }
    }
   }

   return position ;
  }
  #endregion

  #region DrawTree
  private void DrawTree(Node root ,int rowIndex ,int colIndex ,Graphics g ,Point[][] position ,int offsetLeft ,int offsetHigh)
  {   
   if(root == null)
   {
    return ;
   }  
   
   int radius = this.drawParas.Radius ;

   int x = position[rowIndex][colIndex].X*radius  - offsetLeft + radius ;
   int y = position[rowIndex][colIndex].Y*radius  - offsetHigh + radius ;

   
   g.FillEllipse(this.drawParas.BrushNode ,x ,y ,radius*2 ,radius*2) ;
   g.DrawEllipse(this.drawParas.PenNode ,x ,y ,radius*2 ,radius*2) ;   
   
   g.DrawString(root.val.ToString() ,this.drawParas.FontText ,this.drawParas.BrushText ,x+ radius/4 ,y+ radius/4) ;

   //递归
   int x2 = 0 ;
   int y2 = 0 ;
   if(root.leftChild != null)
   {
    int col = 2*colIndex  ;
    x2 = position[rowIndex+1][col].X*radius  - offsetLeft + radius ;
    y2 = position[rowIndex+1][col].Y*radius  - offsetHigh + radius ;
    g.DrawLine(this.drawParas.PenNode ,x + radius/2 ,y + radius/2 ,x2 + radius/2 ,y2 + radius/2) ;
    this.DrawTree(root.leftChild ,rowIndex+1 ,col ,g, position ,offsetLeft ,offsetHigh) ;
   }

   if(root.rightChild != null)
   {
    int col = 2*colIndex +1 ;
    x2 = position[rowIndex+1][col].X*radius  - offsetLeft + radius ;
    y2 = position[rowIndex+1][col].Y*radius  - offsetHigh + radius ;
    g.DrawLine(this.drawParas.PenNode ,x + radius/2 ,y + radius/2 ,x2 + radius/2 ,y2 + radius/2) ;
    this.DrawTree(root.rightChild ,rowIndex+1 ,col ,g, position ,offsetLeft ,offsetHigh) ;
   }
  }

  
  #endregion

  #endregion
 }

整个实现最需要花心思的地方就是各个节点的布局。当每个节点的位置确定后,后续的工作就容易 了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值