二叉树的遍历(非递归)
创始人
2024-05-09 14:00:28
0次

二叉树的遍历

遍历二叉树, 是指按一定的规则和顺序访问二叉树的所有结点, 使每一个结点都被访问一次, 而且只被访问一次.

由于二叉树是非线性结构, 因此, 二叉树的遍历实质上是将二叉树的各个结点排列成一个线性序列.

DFS: 前序, 中序及后序.

BFS: 是指沿着二叉树的宽度优先遍历二叉树的结点, 即从上到下从左到右逐层遍历二叉树的结点.

前序遍历

访问根结点(N), 前序遍历左子树(L), 前序遍历右子树®, 也即NLR.

也可以是NRL, 因为这两种遍历方法都是先访问根结点, 所以没有区别, 掌握其中一种, 另一种也随之掌握.

image-20230109211219716

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

非递归思路: 二叉树的前序遍历

  1. 对于给定根结点root, 依次从根结点root向左路结点遍历, 直到curr为空并在遍历途中访问对应结点的val, 然后将结点依次入栈.
  2. 当curr为空时, pop栈顶结点, 将栈顶结点的右子树根结点赋值给curr, 并继续转换成从根向左路遍历.
	// 二叉树的前序非递归遍历vector preorderTraversal(TreeNode* root) {stack st;vector v;TreeNode* curr=root;while(curr!=nullptr||!st.empty()){   while(curr!=nullptr){v.push_back(curr->val);st.push(curr);curr=curr->left;}TreeNode* top=st.top();st.pop();curr=top->right;/*// 当curr为空时,遍历左路结点的右子树if(curr==nullptr){TreeNode* top=st.top();st.pop();curr=top->right;}else // 当curr不为空时,遍历左路结点{v.push_back(curr->val);st.push(curr);curr=curr->left;}*/}return v;}

中序遍历

中序遍历左子树, 访问根结点, 中序遍历右子树, 也即LNR.

或者RNL.

image-20230109212500640

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

非递归思路: 二叉树的中序遍历

  1. 中序非递归与前序非递归思路相似, 只是访问结点的val时机不同.
  2. 对于给定根结点root, 依次从根结点root向左路结点遍历, 直到curr为空并在遍历途中将结点依次入栈.
  3. 当curr为空时, pop栈顶结点, 先访问栈顶结点的val, 再将栈顶结点的右子树根结点赋值给curr, 并继续转换成从根向左路遍历.
	vector inorderTraversal(TreeNode* root) {std::vector v;std::stack st;TreeNode* curr=root;// 思路与前序遍历相似while(curr!=nullptr || !st.empty()){while(curr!=nullptr){st.push(curr);curr=curr->left;}TreeNode* top=st.top();st.pop();// 只是访问TreeNode的val时机不同v.push_back(top->val);curr=top->right;}return v;// vector v;// stack st;// TreeNode* curr=root;// while(curr!=nullptr || !st.empty())// {//     if(curr!=nullptr)//     {//         st.push(curr);//         curr=curr->left;//     }//     else//     {//         TreeNode* top=st.top();//         st.pop();//         v.push_back(top->val);//         curr=top->right;//     }// }// return v;}

后序遍历

**后序遍历左子树, 后序遍历右子树, 访问根结点, 也即LRN. **

或者RLN.

image-20230109213035617

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。

非递归思路: 二叉树的后序遍历

  1. 后序遍历与前中序遍历有一定差异, 在后序遍历过程中, 需要prev来记录访问结点的前一个, 用来判定该不该访问根结点.
  2. 对于给定根结点root, 依次从根结点root向左路结点遍历, 直到curr为空并在遍历途中将结点依次入栈.
  3. 当curr为空时, 根据栈顶结点的右孩子right, 来判断是否pop. 如果right为空或者right为prev说明右子树为空或者右子树访问完, 所以可以pop,并访问该栈顶结点的val, 最后更新prev.
  4. 如果以上两点不满足, 则说明右子树还未访问, 栈顶元素还不能pop, 需要更新curr为栈顶结点的右孩子继续访问.
	vector postorderTraversal(TreeNode* root) {TreeNode* curr=root;TreeNode* prev=nullptr; // 记录遍历结点的前一个vector v;stack st;while(curr!=nullptr || !st.empty()){while(curr!=nullptr){st.push(curr); // 将结点入栈curr=curr->left;}TreeNode* top=st.top();// 当右子树为空或者右子树被访问过,才popif(top->right==nullptr || top->right==prev){prev=top;v.push_back(top->val);st.pop();}else // 否则先访问右子树,等右子树访问完成,才反过来访问根,不能pop{curr=top->right;}} /*while(curr!=nullptr|| !st.empty()){if(curr!=nullptr){st.push(curr);curr=curr->left;}else{TreeNode* top=st.top();// 当右子树为空或者右子树被访问过,才popif(top->right==nullptr || top->right==prev){    v.push_back(top->val);st.pop();prev=top;}else{curr=top->right;}}}*/return v;}

层序遍历

层序遍历就是根据二叉树的结构从上到下从左到右逐层遍历二叉树的结点.

image-20230109214951059

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

基本思路: 二叉树的层序遍历

  1. 初始化一个队列, 并把根结点入队.
  2. 当队列非空时, 循环执行步骤3到步骤5, 否则遍历结束.
  3. 出队一个结点, 并访问该结点.
  4. 若该结点的左子树非空, 则将其左子树入队.
  5. 若该结点的右子树非空, 则将其右子树入队.

需要注意: 当某一层走完时, 该层的下一层也随之全部进入队列中.

	vector> levelOrder(TreeNode* root) {queue q;vector> vv;int levelSize=0; // 记录某一层有多少个结点if(root!=nullptr){q.push(root);++levelSize; // 刚开始根结点这一层就一个结点}while(!q.empty()){vector v;// 将该层的结点都遍历完for(size_t i=0;iTreeNode* front=q.front();q.pop();v.push_back(front->val);if(front->left!=nullptr){q.push(front->left);}if(front->right!=nullptr){q.push(front->right);}}// 遍历完成,队列中的个数就是下一层结点的个数levelSize=q.size(); vv.push_back(v);}return vv;}if(front->right!=nullptr){q.push(front->right);}}// 遍历完成,队列中的个数就是下一层结点的个数levelSize=q.size(); vv.push_back(v);}return vv;}

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...