對於二叉樹的三種遍歷方法, 遞歸方法實現起來簡單,明白。可是效率很差,而且不安全,可能會棧溢出。循環的實現,確定是基於棧的數據結構來實現,要複雜一些。代碼以下:node
// 前序遍歷 ----基於遞歸 void PreorderTraversal(BinaryTreeNode* pRoot_) { // 爲空時,直接返回了 if (!pRoot_) return; std::cout << pRoot_->m_nValue << " "; PreorderTraversal(pRoot_->m_pLeft); PreorderTraversal(pRoot_->m_pRight); } // 前序遍歷 ----基於循環 void PreorderTraversal_ByCycle(BinaryTreeNode* pRoot_) { // 爲空時,直接返回 if (!pRoot_) return; // 須要使用到棧數據結構, 先把右子樹放到棧中,再把左子樹放到棧中 stack<BinaryTreeNode*> _StackNodes; _StackNodes.push(pRoot_); while (!_StackNodes.empty()) { BinaryTreeNode* _pCurrentNode = _StackNodes.top(); _StackNodes.pop(); std::cout << _pCurrentNode->m_nValue << " "; // 把非空的左右子節點放到棧中, 注意:要先放右節點,再放左節點 BinaryTreeNode* _pRight = _pCurrentNode->m_pRight; BinaryTreeNode* _pLeft = _pCurrentNode->m_pLeft; if (_pRight) _StackNodes.push(_pRight); if (_pLeft) _StackNodes.push(_pLeft); } }
// 中序遍歷 ---- 基於遞歸 void InorderTraversal(BinaryTreeNode* pRoot_) { // 爲空時,直接返回 if (!pRoot_) return; InorderTraversal(pRoot_->m_pLeft); std::cout << pRoot_->m_nValue << " "; InorderTraversal(pRoot_->m_pRight); } // 中序遍歷 ---- 基於循環 void InorderTraversal_ByCycle(BinaryTreeNode* pRoot_) { // 爲空時,直接返回 if (!pRoot_) return; // 初始化一個棧數據結構 std::stack<BinaryTreeNode*> _StackNodes; // 先一股腦地把左子節點放到的棧中, 由於這時棧頂的葉結點就是咱們遍歷的起點 BinaryTreeNode* _pCurrentNode = pRoot_; while (_pCurrentNode) { _StackNodes.push(_pCurrentNode); _pCurrentNode = _pCurrentNode->m_pLeft; } while (!_StackNodes.empty()) { // 遍歷棧頂的節點 BinaryTreeNode* _pCurrentNode = _StackNodes.top(); _StackNodes.pop(); std::cout << _pCurrentNode->m_nValue << " "; // 即然遍歷到了當前的節點,說明了它的左子樹已經遍歷完了,不須要管了。 咱們如今 // 須要關注的是:當前節點的右子樹是否爲空了, 若是不爲空,則須要去處理一下了。 _pCurrentNode = _pCurrentNode->m_pRight; while (_pCurrentNode) { _StackNodes.push(_pCurrentNode); _pCurrentNode = _pCurrentNode->m_pLeft; } } }
// 後序遍歷 ---- 基於遞歸 void PostorderTraversal(BinaryTreeNode* pRoot_) { // 爲空時,直接返回 if (!pRoot_) return; PostorderTraversal(pRoot_->m_pLeft); PostorderTraversal(pRoot_->m_pRight); std::cout << pRoot_->m_nValue << " "; } // 後序遍歷 ---- 基於循環 void PostorderTraversal_ByCycle(BinaryTreeNode* pRoot_) { // 爲空時,直接返回 if (!pRoot_) return; // 使用一個棧的數據結構 std::stack<BinaryTreeNode*> _StackNodes; // 把咱們查找第一個應該遍歷的node的路徑上通過的全部node按順序一股腦地壓入棧中 BinaryTreeNode* _pCurrentNode = pRoot_; while (_pCurrentNode) { _StackNodes.push(_pCurrentNode); // 優先選擇不爲空的左節點,若是左節點爲空,再考慮右節點(右節點爲空也沒有關係) if (_pCurrentNode->m_pLeft) _pCurrentNode = _pCurrentNode->m_pLeft; else _pCurrentNode = _pCurrentNode->m_pRight; } while (!_StackNodes.empty()) { // 遍歷棧頂的節點 BinaryTreeNode* _pCurrentNode = _StackNodes.top(); _StackNodes.pop(); std::cout << _pCurrentNode->m_nValue << " "; // 既然遍歷到了當前節點,說明它的左子樹與右子樹都遍歷完了,不須要管了。咱們如今 // 須要關注的是: 若是當前節點爲父節點的左節點,則須要判斷父節點的右節點是否爲空. // 若是不爲空,則須要去處理父節點的右節點了。 // // 另外,若是當前節點不右父節點的右節點,也不須要管,由於接下來會去遍歷父節點。 if (!_StackNodes.empty() && _pCurrentNode == _StackNodes.top()->m_pLeft) { _pCurrentNode = _StackNodes.top()->m_pRight; while (_pCurrentNode) { _StackNodes.push(_pCurrentNode); // 優先選擇左節點,當左節點爲空時,再選擇右節點(右節點爲空,也沒事) if (_pCurrentNode->m_pLeft) _pCurrentNode = _pCurrentNode->m_pLeft; else _pCurrentNode = _pCurrentNode->m_pRight; } } } }
最後,補充一個寬度優先遍歷的實現,即一層層地遍歷:安全
// 寬度優先遍歷,就是一層層地遍歷。 這確定是基於單端隊列來實現 void BreadthFirstTraversal(BinaryTreeNode* pRoot_) { if (!pRoot_) return; std::queue<BinaryTreeNode*> _QueueNodes; _QueueNodes.push(pRoot_); while (!_QueueNodes.empty()) { BinaryTreeNode* _pCurrentNode = _QueueNodes.front(); _QueueNodes.pop(); std::cout << _pCurrentNode->m_nValue << " "; // 把當前節點的左右非空子節點放入到隊列中 BinaryTreeNode* _pLeft = _pCurrentNode->m_pLeft; BinaryTreeNode* _pRight = _pCurrentNode->m_pRight; if (_pLeft) _QueueNodes.push(_pLeft); if (_pRight) _QueueNodes.push(_pRight); } }