前言
又看了二叉树的遍历的时候,看到了一个大佬的颜色标记法。原文在下面引用处。
觉得很有意思,很多经典的迭代方法也是出于这种方法来的。
但是颜色标记法,就很容易突破障碍,清晰易懂。
一、颜色标记法
核心思想如下:
- 使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
- 如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
- 如果遇到的节点为灰色,则将节点的值输出。
其实只需要一个bool值即可,false 代表没经过过这个节点,true 表示已经经过过了,可以处理了。
实现如下:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<pair<TreeNode*,bool>> stck_tree;
stck_tree.push(make_pair(root,false));
while(!stck_tree.empty())
{
auto [cur,passed] = stck_tree.top();
stck_tree.pop();
if(cur == nullptr) continue;
if(passed ==false)
{
stck_tree.push(make_pair(cur->right,false));//前序遍历
stck_tree.push(make_pair(cur->left,false));
stck_tree.push(make_pair(cur,true));
stck_tree.push(make_pair(cur->right,false));//中序遍历
stck_tree.push(make_pair(cur,true));
stck_tree.push(make_pair(cur->left,false));
stck_tree.push(make_pair(cur,true)); //后序遍历
stck_tree.push(make_pair(cur->right,false));
stck_tree.push(make_pair(cur->left,false));
}
else
result.push_back(cur->val);
}
return result;
}
其中if语句中,三段是三种遍历不同的地方。仅此而已。
是不是简单易懂。
其实并不是要套模板,需要理解了以后随时都能写的出来。而不是死记住模板
二、加强理解
1.入栈顺序
入栈顺序根据遍历的顺序的倒序来即可。
栈是一种 先进后出的结构
所以需要前序 中 左 右做处理的话,就需要 右、左、中 入栈。
这样造成一个节点会两次入栈,也正是利用这种性质来记录了节点处理的顺序。
2. 理解
拿后序遍历来讲。
- 首先从根部开始 root、 right、 left 顺序入栈;
- 弹出left ,将其改变标记为true,再次入栈,同时将其right 、left入栈;
- 一直到最左边的节点,将其入栈后,子树都因为是null 而弹出,最终是其本身开始操作。
- 然后因为其父节点按照root、 right、 left 顺序入栈;本left节点处理完了,再弹出就是right节点的操作了。最后才是root 节点的操作。
- 这样就完成了后序遍历的处理。
这样画一个二叉树,理解一下。
会发现其实就是利用栈的性质,按顺序记录后面要处理的节点。
很多后序遍历的迭代方法,都会用一个pre指针来记录上次处理过的节点,其实也是类似的想法。