计算一棵树的深度和宽度[Treeview的深度和宽度](多题头的表格问题解决的基础)
当我有一棵树,我想知道它的枝叶最深的级别是多少?它有多少个叶子(最终的节点,我称它为宽度)?
用.net怎么来作呢?
这个题目的提出是由于要设计一个多题头的表格而抽象出来的。
动态生成一个多题头的表格如下:
由如下xml描述
完成动态的创建多题头的表格的难点在于,
一棵树的深度和宽读,一个叶枝的级别以及这个叶枝有多少个子叶枝(宽度).
=============================================================
现在我完成一些基本的东西。
先计算一个树的宽度[由此可得到一个节点的宽度的算法]
定义初始宽度
利用递归算法来遍历父节点下面的所有的节点,发现是叶子的则加一
计算树的深度算法我开始想了一个,结果发现有一点问题:
还是先定义初始变量,一个为最大的值,一个为目前的深度值
第一个算法:
基本想法是,遍历所有的节点,如果节点还有子节点则加1,
否则目前深度值置为零。
这个算法对单根线的计算是没有问题的,
但是对于多个子节点的计算是有问题的:
看看图
为了降低解释问题的负责度,我只取这个图树的一个节点来分析。
假如我们的这个树是上图节点1开始(包括节点1下面所有子节点)。
我们看算法是怎么算的。。。
算法遍历的过程是
节点1->节点2->节点3->节点13
此时最大深度_max=4
而_level = 0[因为节点13是叶子]
继续。。
这时递归退回到节点2
节点2->节点4
_level = 1
这个时候已经出现问题,
因为节点2的level是3
而计算出来节点4的深度应该是
_level = 3
计算节点4的深度不应该重新计数
如上图如果按照算法,
节点4的
_level = 1
最后算出来的_max = 5
而真实的值应该为6
现在把算法二改进版
这个算法的想法是确定每个节点的级别,最顶上的是一,
节点向下遍历的时候,子节点的级别为parent level+1,
最大的付给_max,这样就可以得到树的深度了。
用.net怎么来作呢?
这个题目的提出是由于要设计一个多题头的表格而抽象出来的。
动态生成一个多题头的表格如下:
由如下xml描述
1 <item HeaderText="Lifecycle Status (Start Date)" >
2 <item HeaderText="Sample" TitleCss="trTitle2">
3 <item HeaderText="α" ColumnName="sample" TitleCss="trTitle2" Format="d" />
4 <item HeaderText="β" ColumnName="Sampleb" TitleCss="trTitle2" Format="d" />
5 <item HeaderText="ES" ColumnName="SampleES" TitleCss="trTitle2" Format="d" />
6 </item>
7 <item HeaderText="NPI" ColumnName="NPI" TitleCss="trTitle2" Format="d" />
8 <item HeaderText="CEM" ColumnName="CEM" TitleCss="trTitle2" Format="d" />
9
10 </item>
11 <item HeaderText="Under developing and technically immature" >
12 <item HeaderText="Start Date" Width="120" ColumnName="red" TitleCss="trTitle2" Format="d" />
13 <item HeaderText="Sample Available" Width="120" ColumnName="redsample" TitleCss="trTitle2" Format="d" />
14 </item>
2 <item HeaderText="Sample" TitleCss="trTitle2">
3 <item HeaderText="α" ColumnName="sample" TitleCss="trTitle2" Format="d" />
4 <item HeaderText="β" ColumnName="Sampleb" TitleCss="trTitle2" Format="d" />
5 <item HeaderText="ES" ColumnName="SampleES" TitleCss="trTitle2" Format="d" />
6 </item>
7 <item HeaderText="NPI" ColumnName="NPI" TitleCss="trTitle2" Format="d" />
8 <item HeaderText="CEM" ColumnName="CEM" TitleCss="trTitle2" Format="d" />
9
10 </item>
11 <item HeaderText="Under developing and technically immature" >
12 <item HeaderText="Start Date" Width="120" ColumnName="red" TitleCss="trTitle2" Format="d" />
13 <item HeaderText="Sample Available" Width="120" ColumnName="redsample" TitleCss="trTitle2" Format="d" />
14 </item>
完成动态的创建多题头的表格的难点在于,
一棵树的深度和宽读,一个叶枝的级别以及这个叶枝有多少个子叶枝(宽度).
=============================================================
现在我完成一些基本的东西。
先计算一个树的宽度[由此可得到一个节点的宽度的算法]
定义初始宽度
private int _treeWidth = 0 ;
利用递归算法来遍历父节点下面的所有的节点,发现是叶子的则加一
#region 计算树的宽度
/// <summary>
/// 遍历所有节点。
/// 发现节点是树叶则加一
/// 否则,取节点的子节点循环
/// </summary>
/// <param name="node"></param>
private void CountTreeWidth(TreeNode node)
{
if(node.Nodes.Count==0)
this._treeWidth ++;
else
{
for(int i=0;i<node.Nodes.Count;i++)
{
CountTreeWidth(node.Nodes[i]);
}
}
}
#endregion
/// <summary>
/// 遍历所有节点。
/// 发现节点是树叶则加一
/// 否则,取节点的子节点循环
/// </summary>
/// <param name="node"></param>
private void CountTreeWidth(TreeNode node)
{
if(node.Nodes.Count==0)
this._treeWidth ++;
else
{
for(int i=0;i<node.Nodes.Count;i++)
{
CountTreeWidth(node.Nodes[i]);
}
}
}
#endregion
计算树的深度算法我开始想了一个,结果发现有一点问题:
还是先定义初始变量,一个为最大的值,一个为目前的深度值
private int _max = 0;
private int _level =0;
private int _level =0;
第一个算法:
基本想法是,遍历所有的节点,如果节点还有子节点则加1,
否则目前深度值置为零。
#region 算法一
private void CountLevel(TreeNode MyNode)
{
_level++;
if(_level>_max)
_max = _level;
System.Diagnostics.Debug.WriteLine(MyNode.Text);
if(MyNode.Nodes.Count!=0)
{
for(int i=0;i<MyNode.Nodes.Count;i++)
{
System.Diagnostics.Debug.WriteLine(_level);
CountLevel(MyNode.Nodes[i]);
}
}
else
{
System.Diagnostics.Debug.WriteLine(_level);
//_level --;
_level = 0;
}
}
#endregion
private void CountLevel(TreeNode MyNode)
{
_level++;
if(_level>_max)
_max = _level;
System.Diagnostics.Debug.WriteLine(MyNode.Text);
if(MyNode.Nodes.Count!=0)
{
for(int i=0;i<MyNode.Nodes.Count;i++)
{
System.Diagnostics.Debug.WriteLine(_level);
CountLevel(MyNode.Nodes[i]);
}
}
else
{
System.Diagnostics.Debug.WriteLine(_level);
//_level --;
_level = 0;
}
}
#endregion
这个算法对单根线的计算是没有问题的,
但是对于多个子节点的计算是有问题的:
看看图
为了降低解释问题的负责度,我只取这个图树的一个节点来分析。
假如我们的这个树是上图节点1开始(包括节点1下面所有子节点)。
我们看算法是怎么算的。。。
算法遍历的过程是
节点1->节点2->节点3->节点13
此时最大深度_max=4
而_level = 0[因为节点13是叶子]
继续。。
这时递归退回到节点2
节点2->节点4
_level = 1
这个时候已经出现问题,
因为节点2的level是3
而计算出来节点4的深度应该是
_level = 3
计算节点4的深度不应该重新计数
如上图如果按照算法,
节点4的
_level = 1
最后算出来的_max = 5
而真实的值应该为6
现在把算法二改进版
#region 算法二改进
/// <summary>
/// 算法还可以改进
/// 如果知道parent的级别,则本级别则等于parent的level+1
/// </summary>
/// <param name="MyNode"></param>
private void CountLevel3(TreeNode MyNode)
{
_level = 1;
if(MyNode.Parent!=null)
{
MyNode.Tag = (int)MyNode.Parent.Tag + 1;
_level = (int)MyNode.Tag;
}
//getMaxDeep(MyNode);
if(_level>_max)
_max = _level;
for(int i=0;i<MyNode.Nodes.Count;i++)
{
CountLevel3(MyNode.Nodes[i]);
}
}
#endregion
/// <summary>
/// 算法还可以改进
/// 如果知道parent的级别,则本级别则等于parent的level+1
/// </summary>
/// <param name="MyNode"></param>
private void CountLevel3(TreeNode MyNode)
{
_level = 1;
if(MyNode.Parent!=null)
{
MyNode.Tag = (int)MyNode.Parent.Tag + 1;
_level = (int)MyNode.Tag;
}
//getMaxDeep(MyNode);
if(_level>_max)
_max = _level;
for(int i=0;i<MyNode.Nodes.Count;i++)
{
CountLevel3(MyNode.Nodes[i]);
}
}
#endregion
这个算法的想法是确定每个节点的级别,最顶上的是一,
节点向下遍历的时候,子节点的级别为parent level+1,
最大的付给_max,这样就可以得到树的深度了。