一共四种遍历方法:先序遍历、中序遍历、后序遍历、层次遍历。代码的实现方式有两种:递归、迭代。
一、先序遍历
先序遍历就是首先访问根节点,然后访问左节点,最后访问右节点。
1.递归
递归的代码很简单,在递归函数中优先访问根节点然后访问左孩子,最后访问右孩子。
void _PreOrder(PNode& pRoot)
{
if (pRoot)
{
cout << pRoot->_data << " "; //优先输出根节点
_PreOrder(pRoot->_LChild);
_PreOrder(pRoot->_RChild);
}
}
void PreOrder()
{
_PreOrder(_pRoot);
cout << endl;
}
2.迭代
用迭代法对二叉树进行先序遍历需要借助栈;将暂不访问的右孩子压到堆栈中,直到每棵子树的左孩子全部访问完。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> res;
while(root)
{
res.push_back(root->val); //先把根节点访问了
if(root->right) //如果此节点有有孩子,就压栈,以供后续对又孩子进行访问
st.push(root);
root = root->left; //向左子树深入
if(!root&&!st.empty()) //如果左子树都访问完了,并且堆栈中还存在拥有右孩子的节点
{
root = st.top()->right; //根节点更新为其右孩子,并重复判断,进行访问和压栈操作
st.pop();
}
}
return res;
}
};
二、中序遍历
中序遍历就是先访问左孩子,然后访问右孩子,最后访问根节点。
1.递归
递归的代码比较类似。
void _InOrder(PNode& pRoot)
{
if (pRoot)
{
_InOrder(pRoot->_LChild); //优先对左孩子递归
cout << pRoot->_data << " ";
_InOrder(pRoot->_RChild);
}
}
void InOrder()
{
_InOrder(_pRoot);
cout << endl;
}
2.迭代
先将根节点和所有的右孩子全部压栈,然后出栈,首先访问左孩子,然后访问右子树,再讲右子树所有左孩子压栈。。。重复。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> res;
while(root)
{
st.push(root); //对于非空节点无条件压栈
root = root->left; //向左子树深入
if(!root && !st.empty()) //所有左孩子全部进栈
{
root = st.top(); //取出栈顶将要访问的孩子
st.pop();
while(!root->right && !st.empty())
{
res.push_back(root->val); //如果刚才取出的孩子没有右孩子,则只对其进行访问
root = st.top(); //直到找到有右孩子的节点
st.pop();
}
res.push_back(root->val); //对于有右孩子的节点,进行访问
root = root->right; //将其右子树根节点作为根节点进行后面的迭代
}
}
return res;
}
};
三、后序遍历
后序遍历先访问左孩子,然后访问右孩子,最后访问根节点。
1.递归
void _PostOrder(PNode& pRoot)
{
if (pRoot)
{
_PostOrder(pRoot->_LChild); //优先对子节点递归
_PostOrder(pRoot->_RChild);
cout << pRoot->_data << " ";
}
}
void PostOrder()
{
_PostOrder(_pRoot);
cout << endl;
}
2.迭代
迭代后序遍历比较复杂。在遍历完左子树时还不能访问根节点,需要再遍历右子树。待右子树遍历完后才访问根节点。所以在辅助栈工作记录中必须注明节点是在左子树还是在右子树。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> res;
TreeNode* tmp;
while(root)
{
st.push(root);
root = root->left;
if(!root && !st.empty())
{
root = st.top();
while(!root->right && !st.empty())
{
res.push_back(root->val);
st.pop();
if(!st.empty())
root = st.top();
}
tmp = root;
root = root->right;
tmp->right = NULL;
}
}
return res;
}
};
四、层序遍历
程序遍历就是按照从上到下,从左到右的顺序进行遍历。
1.队列实现
void FloorPrint_QUEUE(pTreeNode &Tree) //层序遍历_队列实现
{
queue < pTreeNode> q;
if (Tree != NULL)
{
q.push(Tree); //根节点进队列
}
while (q.empty() == false) //队列不为空判断
{
cout << q.front()->data << " → ";
if (q.front()->leftPtr != NULL) //如果有左孩子,leftChild入队列
{
q.push(q.front()->leftPtr);
}
if (q.front()->rightPtr != NULL) //如果有右孩子,rightChild入队列
{
q.push(q.front()->rightPtr);
}
q.pop(); //已经遍历过的节点出队列
}
}
2.数组实现
void FloorPrint(pTreeNode Tree) //层序遍历
{
pTreeNode temp[100]; //创建pTreeNode指针类型的指针数组
int in = 0;
int out = 0;
temp[in++] = Tree; //先保存二叉树根节点
while (in > out)
{
if (temp[out])
{
cout << temp[out]->data << " → ";
temp[in++] = temp[out]->leftPtr;
temp[in++] = temp[out]->rightPtr;
}
out++;
}
}