最近經常加班,腦子超級不好使,今天被一個很簡單的遞歸搞到了,爲了避免以後重複發生此類事件,將這件醜事記錄下來,提醒自己以後要注意頭腦清醒!!!
這個問題是這樣的,存在樹形結構的列表如下
ID |
Name |
ParentID |
BackUp |
1 |
根 1 |
Null |
Null |
2 |
根 1 子節點 1 |
1 |
|
3 |
根 1 子節點 2 |
1 |
|
4 |
根 1 子節點 2 子節點 1 |
3 |
|
5 |
根 1 子節點 2 子節點 2 |
3 |
|
6 |
根 2 子節點 1 |
7 |
|
7 |
根 2 |
Null |
|
8 |
根 2 子節點 2 |
7 |
|
9 |
根 2 子節點 2 子節點 1 |
8 |
|
10 |
根 2 子節點 2 子節點 1 子節點 1 |
9 |
|
11 |
根 2 子節點 2 子節點 1 子節點 1 子節點 1 |
10 |
|
12 |
根 2 子節點 2 子節點 1 子節點 1 子節點 2 |
10 |
|
典型的樹形結構
將這些數據讀入DataTable dt裏,dt的view和該表結構一樣。由於樹的節點level比較深,用遞歸來的最省事
開始的代碼如下:
public void InitTreeView()
{
for (int i = 0; i <
dt.Rows.Count; i++ )
{
if
(dt.Rows[i][2].ToString() == "")
{
treeView1.Nodes.Add(dt.Rows[i][1].ToString());
treeView1.Nodes[treeView1.Nodes.Count - 1].Tag =
dt.Rows[i][0].ToString();
FillTreeView(treeView1.Nodes,
dt.Rows[i][0].ToString());
}
}
}
public void FillTreeView(TreeNodeCollection tnc, string dtid)
{
DataTable dtcopy = dt.Copy();
dtcopy.DefaultView.RowFilter = "ParentID='" + dtid + "'";
DataTable dtf = dtcopy.DefaultView.ToTable();
foreach (TreeNode
tn in tnc)
{
for (int i = 0; i <
dtf.Rows.Count; i++)
{
if (tn.Tag.ToString() == dtid)
{
tn.Nodes.Add(dtf.Rows[i][1].ToString());
tn.Nodes[tn.Nodes.Count - 1].Tag =
dtf.Rows[i][0].ToString();
}
else
{
FillTreeView(tn.Nodes,
tn.Tag.ToString());
}
}
}
}
在InitTreeView裏,將沒有父ID的值添加爲頂級節點,添加一個節點,指定Tag爲添加值的ID。
我之前寫的時候比較猶豫,一直想添加完一個節點,立刻調用FillTreeView爲其添加子節點,還是添加完本級節點再調用。
但是調用該方法時一直報錯,在使用treeView1.Nodes[dt.Rows[i]["DICTEXT"].ToString()].Nodes
添加時,提示未將對象設置引用到對象的實例。原因應該是treeview的nodes沒有添加完,無法對treeview進行檢索。
但使用FillTreeView(treeView1.Nodes[treeView1.Nodes.Count-1].Nodes)添加,不會報錯,
沒有辦法只好將添加子節點的方法放在了循環外面,這樣就變成了添加0級節點,添加1級節點,添加2級節點....添加N級節點,
顯而易見的,這種做法使算法複雜度大大的提高了。
再來看下FillTreeView方法,
FillTreeView方法的參數爲TreeViewNodeCollection 和父節點ID,由於已經將node的Tag存爲ID了,這裏的dtid就沒有
必要添加了,
而且有一個重要問題,想着用遞歸,並沒有弄清遞歸的調用條件,就是沒搞清什麼時候調用自己,是應該在添加完本個節點後
就調用呢還是添加完本級節點再調用,最終結果是層層添加後倒騰出來了
public void InitTreeView()
{
for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i][2].ToString() == "")
{
treeView1.Nodes.Add(dt.Rows[i][1].ToString());
treeView1.Nodes[treeView1.Nodes.Count - 1].Tag = dt.Rows[i][0].ToString();
}
} FillTreeView(treeView1.Nodes);
}
public void FillTreeView(TreeNodeCollection tnc)
{
foreach (TreeNode tn in tnc)
{
DataTable dtcopy = dt.Copy();
dtcopy.DefaultView.RowFilter = "ParentID='" + tn.Tag + "'";
DataTable dtf = dtcopy.DefaultView.ToTable();
for (int i = 0; i < dtf.Rows.Count; i++)
{
tn.Nodes.Add(dtf.Rows[i][1].ToString());
tn.Nodes[tn.Nodes.Count - 1].Tag = dtf.Rows[i][0].ToString();
}
FillTreeView(tn.Nodes);
}
}
哎,寫碼時,考慮太多,導致整個代碼的臃腫