首页 > 其他分享 >二叉树的非递归遍历

二叉树的非递归遍历

时间:2024-04-07 23:35:53浏览次数:14  
标签:遍历 TreeNode nodestack 递归 current right 二叉树 root 节点

感谢b站up主优雅的代码:https://space.bilibili.com/95715842

二叉树的非递归遍历

非递归的先序遍历

思想:利用栈先进后出的性质。将根节点入栈,(根节点出栈的同时先拉右子树入栈,之后拉左子树入栈;左子树出栈的同时先拉其右子树入栈);依次继续。

void preOrder(TreeNode *root) {
    if (root == NULL)  return ;
    stack<TreeNode *> nodestack;
    nodestack.push(root);   // 根节点入栈

    while(!nodestack.empty()){  // 栈不为空
        TreeNode *node = nodestack.top();   // 保存栈顶节点
        printf("%d ", node->val);
        nodestack.pop();    // 出栈
        
        if(node->right) nodestack.push(node->right);
        if(node->left) nodestack.push(node->left);
    }
}

非递归的中序遍历

思想:寻找最左子树。(先将根节点入栈,我们要额外使用一个current指向当前节点;我们沿着根节点一直往左走寻找最左子树,current指向当前遍历的位置;找到最左子树后,最左子树出栈并将右子树入栈,current指向右子树);重复这个过程。

void InOrder(TreeNode *root) {
    if (root == NULL)   return ;
    stack<TreeNode *> nodestack;
    TreeNode *current = root;   // 维护一个current指针

    while(current || !nodestack.empty()) {
        // 当前节点非空,沿着左子树入栈
        while(current) {
            nodestack.push(current);
            current = current->left;
        }
        // 此时栈顶节点没有左子树,或已经访问完左子树
        current = nodestack.top();  // 去栈顶节点
        printf("%d ", current->val);
        nodestack.pop();    // 出栈
        current = current->right;   // 右子树入栈
    }
}

非递归的后序遍历

思想:不断的检查是否有右子树。(先将根节点入栈,沿着左子树的方向入栈,直到左子树所有结点入栈时,弹出栈顶元素时检查栈顶元素是否具有右子树,如果有右子树就入栈);重复这个过程。

void postOrder(TreeNode *root) {
    if (root == NULL)   return ;
    TreeNode *current = root;   // 维护一个current指针
    TreeNode *visit = root;    // 维护一个visit指针,利用二叉树无环图的性质

    stack<TreeNode *> nodestack;
    // 当前节点非空,或栈不为空
    while(current || !nodestack.empty()) {
        while(current) {
            nodestack.push(current);    // 当前节点入栈
            current = current->left;    // 沿着左子树入栈
        }
        // 此时栈顶节点没有左子树,或已经访问完左子树
        current = nodestack.top();  // 取栈顶节点
        // 如果栈顶节点有右子树,且未被访问过
        if(current->right && current->right != visit) {
            current = current->right;   // 右子树入栈
        } else {
            printf("%d ", current->val);
            visit = current;    // 标记当前节点已被访问
            current = NULL;     // 当前节点置空
            nodestack.pop();    // 出栈
        }
    }
}

完整代码

#include <iostream>
#include <stack>
using namespace std;

struct TreeNode {
  int val; // 节点值
  TreeNode *left;
  TreeNode *right;
  TreeNode(int x): val(x), left(nullptr), right(nullptr) {}
};

void preOrder(TreeNode *root) {
    if (root == NULL)  return ;
    stack<TreeNode *> nodestack;
    nodestack.push(root);   // 根节点入栈

    while(!nodestack.empty()){  // 栈不为空
        TreeNode *node = nodestack.top();   // 保存栈顶节点
        printf("%d ", node->val);
        nodestack.pop();    // 出栈
        
        if(node->right) nodestack.push(node->right);
        if(node->left) nodestack.push(node->left);
    }
}

void InOrder(TreeNode *root) {
    if (root == NULL)   return ;
    stack<TreeNode *> nodestack;
    TreeNode *current = root;   // 维护一个current指针

    while(current || !nodestack.empty()) {
        // 当前节点非空,沿着左子树入栈
        while(current) {
            nodestack.push(current);
            current = current->left;
        }
        // 此时栈顶节点没有左子树,或已经访问完左子树
        current = nodestack.top();  // 去栈顶节点
        printf("%d ", current->val);
        nodestack.pop();    // 出栈
        current = current->right;   // 右子树入栈
    }
}

void postOrder(TreeNode *root) {
    if (root == NULL)   return ;
    TreeNode *current = root;   // 维护一个current指针
    TreeNode *visit = root;    // 维护一个visit指针,利用二叉树无环图的性质

    stack<TreeNode *> nodestack;
    // 当前节点非空,或栈不为空
    while(current || !nodestack.empty()) {
        while(current) {
            nodestack.push(current);    // 当前节点入栈
            current = current->left;    // 沿着左子树入栈
        }
        // 此时栈顶节点没有左子树,或已经访问完左子树
        current = nodestack.top();  // 取栈顶节点
        // 如果栈顶节点有右子树,且未被访问过
        if(current->right && current->right != visit) {
            current = current->right;   // 右子树入栈
        } else {
            printf("%d ", current->val);
            visit = current;    // 标记当前节点已被访问
            current = NULL;     // 当前节点置空
            nodestack.pop();    // 出栈
        }
    }
}

int main(){
    // 初始化节点
    TreeNode* n1 = new TreeNode(1);
    TreeNode* n2 = new TreeNode(2);
    TreeNode* n3 = new TreeNode(3);
    TreeNode* n4 = new TreeNode(4);
    TreeNode* n5 = new TreeNode(5);

    // 构建节点之间的引用(指针)
    n1->left = n2;
    n1->right = n3;
    n2->left = n4;
    n2->right = n5;

    preOrder(n1);
    printf("\n");
    InOrder(n1);
    printf("\n");
    postOrder(n1);
    return 0;
}

标签:遍历,TreeNode,nodestack,递归,current,right,二叉树,root,节点
From: https://www.cnblogs.com/moguw/p/18120165

相关文章

  • 数据结构之二叉树 - 超详细的教程,手把手教你认识并运用二叉树
    目录1.树形结构(了解)1.1树形结构的概念(重要)1.2 树的表示形式(了解)1.3 树的应用2.二叉树(重点)2.1概念2.2两种特殊的二叉树2.3二叉树的性质2.4二叉树的存储2.5二叉树的基本操作2.5.1二叉树的遍历1.前序遍历2.中序遍历3.后序遍历4.层序遍历2.5.2......
  • Acwing2024蓝桥杯递归
    模板:欧几里得算法//若a,b互质则返回1,否则返回0intgcd(inta,intb){returnb?gcd(b,a%b):a;}题目:AcWing1360.有序分数暴力模拟法(AC):#include<iostream>#include<algorithm>#definexfirst#defineysecondusingnamespacestd;intn;typed......
  • bs4的使用 遍历文档树
     bs4的使用#遍历文档树#搜索文档树(5种过滤规则)#limit和recursive参数importrequests#pip3installbeautifulsoup4解析html和xml,修改html和xmlfrombs4importBeautifulSoup#res=requests.get('https://www.autohome.com.cn/news/1/#liststart')##withop......
  • 图的遍历试题解析
    一、单项选择题01.下列关于广度优先算法的说法中,正确的是(A ).Ⅰ.当各边的权值相等时,广度优先算法可以解决单源最短路径问题Ⅱ.当各边的权值不等时,广度优先算法可用来解决单源最短路径问题Ⅲ.广度优先遍历算法类似于树中的后序遍历算法Ⅳ.实现图的广度优先算法时,使用的......
  • 从数组创建二叉树-Leetcode测试用
    Leetcode里和二叉树相关的题目,都是用一个数组表示二叉树的,而这个数组是按照层次优先顺序给出的,连其中的空结点也表示了出来,刚好就是2^N-1个结点,N表示层数。但数组毕竟无法和二叉树一样具有链式结构,无法进行算法测试,因此尝试直接通过这样的数组构建二叉树。通过数组创建这样的二......
  • 二叉树-统一迭代法
    迭代法实现的前中后序遍历,除了前序和后序相互关联,中序则是另一种风格。我们需要针对三种遍历方式实现统一风格的代码。如何统一风格:解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况。将访问的节点放入栈中,把要处理的节点放入栈中但是做标记(紧接着放入一个空指针)......
  • 18天【代码随想录算法训练营34期】● 513.找树左下角的值 ● 112. 路径总和 113.路径
    513.找树左下角的值#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#self.left=left#self.right=rightclassSolution:deffindBottomLeftValue(self......
  • 二叉树-迭代遍历
    递归的实现是每次递归调用都把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候就从栈顶弹出上一次递归的各项参数。可利用栈实现二叉树的前中后序遍历。前序遍历前序遍历是中左右的顺序,整体过程就是逐次访问父节点,压入右孩子再压入左孩子,由于访问的节点和待......
  • 2.手写JavaScript广度和深度优先遍历二叉树
    一、核心思想:1.深度遍历:依靠栈先进后出的机制,分别设置返回结果的数组和栈数组,首先判断栈非空,对每个结点,将其出栈并把值push到结果数组,判断是否有右左孩子,分别将其加入栈中,循环执行上述操作。否则返回结果数组。2.广度遍历:依靠队列先进先出的机制,分别设置返回结果的数组和队......
  • 17天【代码随想录算法训练营34期】第六章 二叉树part04(● 110.平衡二叉树 ● 257.
    110.平衡二叉树#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#self.left=left#self.right=rightclassSolution:defgetDepth(self,root):......