二叉树的前序/中序/后序遍历方法的递归与循环的实现
Posted yinheyi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的前序/中序/后序遍历方法的递归与循环的实现相关的知识,希望对你有一定的参考价值。
对于二叉树的三种遍历方法, 递归方法实现起来简单,明白。但是效率不好,并且不安全,可能会栈溢出。循环的实现,肯定是基于栈的数据结构来实现,要复杂一些。代码如下:
前序遍历的实现:
// 前序遍历 ----基于递归 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); } }
以上是关于二叉树的前序/中序/后序遍历方法的递归与循环的实现的主要内容,如果未能解决你的问题,请参考以下文章