二叉树的统一迭代法

二叉树的统一迭代法 此时我们在二叉树:一入递归深似海,从此offer是路人中用递归的方式,实现了二叉树前中后序的遍历。
在二叉树:听说递归能做的,栈也能做!中用栈实现了二叉树前后中序的迭代遍历(非递归)。
之后我们发现迭代法实现的先中后序,其实风格也不是那么统一,除了先序和后序,有关联,中序完全就是另一个风格了,一会用栈遍历,一会又用指针来遍历。
实践过的同学,也会发现使用迭代法实现先中后序遍历,很难写出统一的代码,不像是递归法,实现了其中的一种遍历方式,其他两种只要稍稍改一下节点顺序就可以了。
其实针对三种遍历方式,使用迭代法是可以写出统一风格的代码!
重头戏来了,接下来介绍一下统一写法。
我们以中序遍历为例,在二叉树:听说递归能做的,栈也能做!中提到说使用栈的话,无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况。
那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。
如何标记呢,就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。 这种方法也可以叫做标记法。
迭代法中序遍历 中序遍历代码如下:(详细注释)
class solution {public:    vector inordertraversal(treenode* root) {        vector result;        stack st;        if (root != null) st.push(root);        while (!st.empty()) {            treenode* node = st.top();            if (node != null) {                st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中                if (node->right) st.push(node->right);  // 添加右节点(空节点不入栈)                st.push(node);                          // 添加中节点                st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。                if (node->left) st.push(node->left);    // 添加左节点(空节点不入栈)            } else { // 只有遇到空节点的时候,才将下一个节点放进结果集                st.pop();           // 将空节点弹出                node = st.top();    // 重新取出栈中元素                st.pop();                result.push_back(node->val); // 加入到结果集            }        }        return result;    }}; 看代码有点抽象我们来看一下动画(中序遍历):
中序遍历迭代(统一写法) 动画中,result数组就是最终结果集。
可以看出我们将访问的节点直接加入到栈中,但如果是处理的节点则后面放入一个空节点, 这样只有空节点弹出的时候,才将下一个节点放进结果集。
此时我们再来看前序遍历代码。
迭代法前序遍历 迭代法前序遍历代码如下:(注意此时我们和中序遍历相比仅仅改变了两行代码的顺序)
class solution {public:    vector preordertraversal(treenode* root) {        vector result;        stack st;        if (root != null) st.push(root);        while (!st.empty()) {            treenode* node = st.top();            if (node != null) {                st.pop();                if (node->right) st.push(node->right);  // 右                if (node->left) st.push(node->left);    // 左                st.push(node);                          // 中                st.push(null);            } else {                st.pop();                node = st.top();                st.pop();                result.push_back(node->val);            }        }        return result;    }}; 迭代法后序遍历 后续遍历代码如下:(注意此时我们和中序遍历相比仅仅改变了两行代码的顺序)
class solution {public:    vector postordertraversal(treenode* root) {        vector result;        stack st;        if (root != null) st.push(root);        while (!st.empty()) {            treenode* node = st.top();            if (node != null) {                st.pop();                st.push(node);                          // 中                st.push(null);                if (node->right) st.push(node->right);  // 右                if (node->left) st.push(node->left);    // 左            } else {                st.pop();                node = st.top();                st.pop();                result.push_back(node->val);            }        }        return result;    }}; 总结 此时我们写出了统一风格的迭代法,不用在纠结于前序写出来了,中序写不出来的情况了。
但是统一风格的迭代法并不好理解,而且想在面试直接写出来还有难度的。
所以大家根据自己的个人喜好,对于二叉树的前中后序遍历,选择一种自己容易理解的递归和迭代法。
其他语言版本 java:迭代法前序遍历代码如下:
class solution {    public list preordertraversal(treenode root) {        list result = new linkedlist();        stack st = new stack();        if (root != null) st.push(root);        while (!st.empty()) {            treenode node = st.peek();            if (node != null) {                st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中                if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)                if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)                st.push(node);                          // 添加中节点                st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。                            } else { // 只有遇到空节点的时候,才将下一个节点放进结果集                st.pop();           // 将空节点弹出                node = st.peek();    // 重新取出栈中元素                st.pop();                result.add(node.val); // 加入到结果集            }        }        return result;    }} 迭代法中序遍历代码如下:
class solution {public list inordertraversal(treenode root) {        list result = new linkedlist();    stack st = new stack();    if (root != null) st.push(root);    while (!st.empty()) {        treenode node = st.peek();        if (node != null) {            st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中            if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)            st.push(node);                          // 添加中节点            st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。            if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)        } else { // 只有遇到空节点的时候,才将下一个节点放进结果集            st.pop();           // 将空节点弹出            node = st.peek();    // 重新取出栈中元素            st.pop();            result.add(node.val); // 加入到结果集        }    }    return result;}} 迭代法后序遍历代码如下:
class solution {   public list postordertraversal(treenode root) {        list result = new linkedlist();        stack st = new stack();        if (root != null) st.push(root);        while (!st.empty()) {            treenode node = st.peek();            if (node != null) {                st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中                st.push(node);                          // 添加中节点                st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。                if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)                if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)                                                    } else { // 只有遇到空节点的时候,才将下一个节点放进结果集                st.pop();           // 将空节点弹出                node = st.peek();    // 重新取出栈中元素                st.pop();                result.add(node.val); // 加入到结果集            }        }        return result;   }} python:
迭代法前序遍历:
class solution:    def preordertraversal(self, root: treenode) -> list[int]:        result = []        st= []        if root:            st.append(root)        while st:            node = st.pop()            if node != none:                if node.right: #右                    st.append(node.right)                if node.left: #左                    st.append(node.left)                st.append(node) #中                st.append(none)            else:                node = st.pop()                result.append(node.val)        return result 迭代法中序遍历:
class solution:    def inordertraversal(self, root: treenode) -> list[int]:        result = []        st = []        if root:            st.append(root)        while st:            node = st.pop()            if node != none:                if node.right: #添加右节点(空节点不入栈)                    st.append(node.right)                                st.append(node) #添加中节点                st.append(none) #中节点访问过,但是还没有处理,加入空节点做为标记。                                if node.left: #添加左节点(空节点不入栈)                    st.append(node.left)            else: #只有遇到空节点的时候,才将下一个节点放进结果集                node = st.pop() #重新取出栈中元素                result.append(node.val) #加入到结果集        return result 迭代法后序遍历:
class solution:    def postordertraversal(self, root: treenode) -> list[int]:        result = []        st = []        if root:            st.append(root)        while st:            node = st.pop()            if node != none:                st.append(node) #中                st.append(none)                                if node.right: #右                    st.append(node.right)                if node.left: #左                    st.append(node.left)            else:                node = st.pop()                result.append(node.val)        return result


掌握开关稳压器的5大基本知识(下)
AI+教育大势所趋,人工智能怎么培养人才?
成型机料位测量常见问题及应对办法
总投资20亿元,泽石固态硬盘模组及芯片封测生产基地签约落户
面对人工智能的发展 人类未来将扮演怎样的角色?
二叉树的统一迭代法
浙江富润与紫光国微达成战略合作 将提升5G用户体验
领跑全球!中国6G那些激动人心的瞬间
反相比例运放电路原理图解析
英国使用华为5G设备已在6个城部分地区率先启动了商用5G服务
利用多内核处理器的并行编程功能实现视频代码转换
意大利沃达丰CEO力挺华为:称华为为5G最佳合作伙伴 将继续保持合作
反向偏置霍尔效应开关的接近感应编程技术
泛在电力物联网怎样来加快应用落地
摩尔定律放缓后,AMD都迎来了哪些创新呢?
选频放大器的工作原理与双T电桥的频率特性
税务局“税收大数据”助力藏鄂企业复工
变频电视调谐器MAX3542
合肥高新区力争挺进集成电路产业全国前五位 打造中国IC之都
金属箔式应变片—电桥性能实验