當時想這個算法的時候,是先想好了extjs的格式轉換方法后才寫的,寫完后也沒有考慮extjs是不是可以直接用{ ‘id’:’’,’pid’:’’,’text’:’’}格式的方式來表示呢?呵呵,如果是的話那就郁悶了~~,不管了。為了使用Extjs實現(xiàn)在客戶端顯示樹形節(jié)點,需要獲得節(jié)點的孩子節(jié)點集合。于是,花了三個小時時間寫出了一個遍歷算法(囧,代碼編寫能力還有待提高啊,有時候這中間的關系搞得我暈頭轉向的,不得不一邊畫圖以便寫代碼~~),由children字段為空的List<TreeNode> 分析并返回一個包含children的根節(jié)點樹以便生成json數(shù)據(jù)。
算法思想如下:
1)當nodelist中還有節(jié)點存在時,取出nodeList中的一個節(jié)點,并將其從nodeList中移除,進行2)
2)采用深度遍歷算法,每取一個節(jié)點,將其壓入堆棧,因為nodelist中不包含根節(jié)點,故建立一個root節(jié)點,進行3)
3)在循環(huán)中判斷當前節(jié)點是否為空(即已加入為root節(jié)點的children集合),不為空則進行4),否則到exit)。
4)取出棧頂節(jié)點。判斷該節(jié)點是否有未加入children集合的孩子節(jié)點(即在nodeList中能否找到
pid為節(jié)點id的節(jié)點),有則進行5),否則進行6)
5)將該節(jié)點取出,并將其從nodeList中刪除,入棧,繼續(xù)查找,返回3)
6)若當前節(jié)點沒有孩子結點,到7)
7)此時,判斷堆棧是否為空,若為空(表示此時當前節(jié)點所有的子節(jié)點已找完),到8),若棧不為空,到9)
8)當前節(jié)點為葉子節(jié)點,棧頂節(jié)點即為當前節(jié)點的父節(jié)點。出棧,將子節(jié)點加入到父節(jié)點的children集合中。父節(jié)點再入棧。到3)
9)判斷當前節(jié)點是否還有父節(jié)點(即判斷nodeList中是否還有id為當前節(jié)點pid的節(jié)點),若有,到10),否則到11)
10)取出該節(jié)點為pNode,并將pNode從nodeList中刪除,將當前節(jié)點cNode加入到pNode的children集合中,
即作為父節(jié)點的孩子節(jié)點,父節(jié)點入棧(父節(jié)點還可能有別的孩子結點)。到3)
11)表示當前節(jié)點為頂級節(jié)點,將其直接加入到root的children中。到3)
因為每找到一個子節(jié)點均將齊從nodelist中移除,故當前節(jié)點的子節(jié)點最終都會找完
exit)程序結束。此時返回的root節(jié)點即為完整的多叉樹的根節(jié)點,可通過其孩子集合來對節(jié)點進行訪問,并
通過json的方法進行樹形數(shù)據(jù)格式的轉換。
public class TreeNodeHelper { /// <summary> /// 生成一個根節(jié)點的樹 /// </summary> /// <param name="nodeList">節(jié)點列表,包含未連接的樹節(jié)點,節(jié)點中給出id,pid,text字段</param> /// <returns></returns> public TreeNode GenerateTreeRoot(List<TreeNode> nodeList) { TreeNode root = new TreeNode(); TreeNode cNode; TreeNode chNode; TreeNode pNode; Stack<TreeNode> stack = new Stack<TreeNode>(); while(nodeList.Count>0) { cNode = nodeList[0]; nodeList.Remove(cNode); stack.Push(cNode); while (cNode != null) { cNode = stack.Pop(); if ((chNode = getChildren(cNode, nodeList)) != null) { stack.Push(cNode); nodeList.Remove(chNode); stack.Push(chNode); } else { if (stack.Count > 0) { pNode = stack.Pop(); pNode.Children.Add(cNode); stack.Push(pNode); } else { if((pNode=getParent(cNode,nodeList))!=null) { nodeList.Remove(pNode); stack.Push(pNode); pNode.Children.Add(cNode); } else { root.Children.Add(cNode); cNode = null; } } } } } return root; } public TreeNode getChildren(TreeNode node, List<TreeNode> list) { return list.Find(delegate(TreeNode n) { return n.Pid == node.Id; }); } public TreeNode getParent(TreeNode node, List<TreeNode> list) { return list.Find(delegate(TreeNode n) { return n.Id == node.Pid; }); } }
下面是節(jié)點類的定義:
public class TreeNode { public TreeNode() { m_Id = String.Empty; m_Pid = String.Empty; m_Text = String.Empty; m_Children = new List<TreeNode>(); } public TreeNode(string id, string pid, string text) { m_Id = id; m_Pid = pid; m_Text = text; m_Children = new List<TreeNode>(); } private string m_Id; public string Id { get { return m_Id; } set { m_Id = value; } } private string m_Pid; public string Pid { get { return m_Pid; } set { m_Pid = value; } } private string m_Text; public string Text { get { return m_Text; } set { m_Text = value; } } private List<TreeNode> m_Children; public List<TreeNode> Children { get { return m_Children; } set { m_Children = value; } } public bool HasChildren { get { if (this.Children != null) return m_Children.Count > 0 ? true : false; else return false; } } /// <summary> /// 生成根節(jié)點的json格式字符串 /// </summary> /// <returns></returns> public string ToJsonTreeString() { if (!this.HasChildren) return ""; StringBuilder sb = new StringBuilder(); sb.Append("["); foreach (TreeNode node in this.Children) { sb.Append("{"); sb.Append("'id':'"); sb.Append(node.Id); sb.Append("','text':'"); sb.Append(node.Text); sb.Append("',"); //有孩子節(jié)點時添加children字段,否則令leaf字段為true if (node.HasChildren) { sb.Append("'children':"); sb.Append(node.ToJsonTreeString()); } else { sb.Append("'leaf':true"); } sb.Append("},"); } //去掉最后一個逗號 if(this.Children.Count>0) sb.Remove(sb.ToString().LastIndexOf(','), 1); sb.Append("]"); return sb.ToString(); } }
代碼寫的比較菜,歡迎扔磚,共同進步