樹結構的深度優先遍歷是應用中常見的問題ios
在實際項目中,多叉樹出現的比較廣泛,經常使用來存儲相似字典詞條的路徑信息。spa
多叉樹對於在一個序列中找到前綴匹配的全部路徑是可行的選擇,例如找到一段文字中全部前綴匹配的詞條(中國人民解放軍爲例,有中,中國,中國人,中國人民,中國人民解放軍等匹配詞條)。code
構造一棵包含全部中文詞條的字典樹,能夠經過深度優先遍歷快速解析出這些前綴匹配的詞條,樹的每個節點都是一個漢字,爾從根節點出發的路徑是存儲的中文詞條。接口
如下的代碼是一段示例,它的遍歷會輸出全部的葉子節點。ci
樹結構是一個名爲Tree的類型模板,其中存儲了TreeData類型的有效數據,使用定義的接口能夠存儲路徑到Tree結構中。element
遍歷的類型TreeTraverser,使用了一個棧來記錄遍歷的當前路徑,其類型是自定義的TraverStack類型,表示一個節點和它未被遍歷的孩子,棧中每一個節點未遍歷的孩子的序列實現上使用了一個vector序列容器記錄,便於回溯的時候訪問下一個未訪問的孩子節點。
it
#include<iostream> #include<stack> #include<queue> #include<cassert> #include<algorithm> using namespace std; template<class TreeData> struct Tree { private: static int TreeDataCompare(Tree* op1, Tree* op2) { return op1->GetData() - op2->GetData(); } public: Tree(TreeData data): m_data(data) { } public: void AppendChild(Tree* child) { m_children.push_back(child); // sort children trees by treedata sort(m_children.begin(), m_children.end(), TreeDataCompare); } Tree* PutChildByData(TreeData data) { // data already exists for(int i = 0; i < m_children.size(); i++) if(data == m_children[i]->GetData()) return m_children[i]; // Append new child to children array Tree* newChild = new Tree(data); AppendChild(newChild); return newChild; } void PutPathByDataArray(const TreeData* szData) { if (*szData == 0) return; Tree* child = PutChildByData(*szData); child->PutPathByDataArray(szData+1); } private: TreeData m_data; vector<Tree*> m_children; public: int GetChildrenNum() { return m_children.size(); } Tree* GetChildByIndex(int index) { return m_children[index]; } TreeData GetData() { return m_data; } // Fill children to the specified queue virtual void FillQueueWithChildren(queue<Tree*>& queue) { for(int i = 0; i < m_children.size(); i++) { if(m_children[i]) queue.push(m_children[i]); } } }; template<class Tree> class TraverseStack { public: TraverseStack(Tree* tree): m_tree(tree) { m_tree->FillQueueWithChildren(m_children); } Tree* GetNextChild() { if (m_children.empty()) return NULL; // pop head of the untraversed children queue Tree* head = m_children.front(); m_children.pop(); return head; } Tree* GetTree() { return m_tree; } private: Tree* m_tree; queue<Tree*> m_children; }; template<class Tree> class BFSTraverser { public: BFSTraverser(Tree* root):m_root(root){} virtual ~BFSTraverser(){} public: typedef TraverseStack<Tree> PATHSTACKITEM; typedef vector<PATHSTACKITEM > PATHSTACK; public: virtual void Traverse() { m_pathStack.clear(); // push the root stack item PATHSTACKITEM rItem(m_root); m_pathStack.push_back(rItem); while(!m_pathStack.empty()) { PATHSTACKITEM& top = m_pathStack.back(); //cout << "Get top = " << top.GetTree()->GetData() << endl; Tree* nextChild = top.GetNextChild(); if (!nextChild) { // output pathStack if(top.GetTree()->GetChildrenNum() == 0) OutputStack(); // go back along the path to parent TraverseStack element m_pathStack.pop_back(); continue; } assert(nextChild); // pre order output root's path if(nextChild == top.GetTree()->GetChildByIndex(0)) ;//OutputStack(); // push new TraverseStack element to path PATHSTACKITEM newStackItem(nextChild); // enlonger the current path to the untraversed child m_pathStack.push_back(newStackItem); continue; } } private: void OutputStack() { for(int i = 1; i < m_pathStack.size(); i++) { if(i>0) ;//cout << ","; cout << m_pathStack[i].GetTree()->GetData(); } cout << endl; } private: Tree* m_root; PATHSTACK m_pathStack; };