二叉树绘制器BinaryTreeDrawer实现

二叉树绘制器的实现与节点布局
博客介绍了二叉树绘制器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
{
privateDrawerParas 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
}

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值