文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一个套路,写出来二叉树的迭代遍历

2024-12-03 01:52

关注

在二叉树:听说递归能做的,栈也能做!中用栈实现了二叉树前后中序的迭代遍历(非递归)。

之后我们发现迭代法实现的先中后序,其实风格也不是那么统一,除了先序和后序,有关联,中序完全就是另一个风格了,一会用栈遍历,一会又用指针来遍历。

实践过的同学,也会发现使用迭代法实现先中后序遍历,很难写出统一的代码,不像是递归法,实现了其中的一种遍历方式,其他两种只要稍稍改一下节点顺序就可以了。

其实针对三种遍历方式,使用迭代法是可以写出统一风格的代码!

重头戏来了,接下来介绍一下统一写法。

我们以中序遍历为例,在二叉树:听说递归能做的,栈也能做!中提到说使用栈的话,无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况。

那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。

如何标记呢,就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。 这种方法也可以叫做标记法。

迭代法中序遍历

中序遍历代码如下:(详细注释)

  1. class Solution { 
  2. public
  3.     vector<int> inorderTraversal(TreeNode* root) { 
  4.         vector<int> result; 
  5.         stack st; 
  6.         if (root != NULL) st.push(root); 
  7.         while (!st.empty()) { 
  8.             TreeNode* node = st.top(); 
  9.             if (node != NULL) { 
  10.                 st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中 
  11.                 if (node->right) st.push(node->right);  // 添加右节点(空节点不入栈) 
  12.  
  13.                 st.push(node);                          // 添加中节点 
  14.                 st.push(NULL); // 中节点访问过,但是还没有处理,加入空节点做为标记。 
  15.  
  16.                 if (node->left) st.push(node->left);    // 添加左节点(空节点不入栈) 
  17.             } else { // 只有遇到空节点的时候,才将下一个节点放进结果集 
  18.                 st.pop();           // 将空节点弹出 
  19.                 node = st.top();    // 重新取出栈中元素 
  20.                 st.pop(); 
  21.                 result.push_back(node->val); // 加入到结果集 
  22.             } 
  23.         } 
  24.         return result; 
  25.     } 
  26. }; 

看代码有点抽象我们来看一下动画(中序遍历):

中序遍历迭代(统一写法)

动画中,result数组就是最终结果集。

可以看出我们将访问的节点直接加入到栈中,但如果是处理的节点则后面放入一个空节点, 这样只有空节点弹出的时候,才将下一个节点放进结果集。

此时我们再来看前序遍历代码。

迭代法前序遍历

迭代法前序遍历代码如下:(注意此时我们和中序遍历相比仅仅改变了两行代码的顺序)

  1. class Solution { 
  2. public
  3.     vector<int> preorderTraversal(TreeNode* root) { 
  4.         vector<int> result; 
  5.         stack st; 
  6.         if (root != NULL) st.push(root); 
  7.         while (!st.empty()) { 
  8.             TreeNode* node = st.top(); 
  9.             if (node != NULL) { 
  10.                 st.pop(); 
  11.                 if (node->right) st.push(node->right);  // 右 
  12.                 if (node->left) st.push(node->left);    // 左 
  13.                 st.push(node);                          // 中 
  14.                 st.push(NULL); 
  15.             } else { 
  16.                 st.pop(); 
  17.                 node = st.top(); 
  18.                 st.pop(); 
  19.                 result.push_back(node->val); 
  20.             } 
  21.         } 
  22.         return result; 
  23.     } 
  24. }; 

迭代法后序遍历

后续遍历代码如下:(注意此时我们和中序遍历相比仅仅改变了两行代码的顺序)

  1. class Solution { 
  2. public
  3.     vector<int> postorderTraversal(TreeNode* root) { 
  4.         vector<int> result; 
  5.         stack st; 
  6.         if (root != NULL) st.push(root); 
  7.         while (!st.empty()) { 
  8.             TreeNode* node = st.top(); 
  9.             if (node != NULL) { 
  10.                 st.pop(); 
  11.                 st.push(node);                          // 中 
  12.                 st.push(NULL); 
  13.  
  14.                 if (node->right) st.push(node->right);  // 右 
  15.                 if (node->left) st.push(node->left);    // 左 
  16.  
  17.             } else { 
  18.                 st.pop(); 
  19.                 node = st.top(); 
  20.                 st.pop(); 
  21.                 result.push_back(node->val); 
  22.             } 
  23.         } 
  24.         return result; 
  25.     } 
  26. }; 

总结

此时我们写出了统一风格的迭代法,不用在纠结于前序写出来了,中序写不出来的情况了。

但是统一风格的迭代法并不好理解,而且想在面试直接写出来还有难度的。

所以大家根据自己的个人喜好,对于二叉树的前中后序遍历,选择一种自己容易理解的递归和迭代法。

其他语言版本

Java:迭代法前序遍历代码如下:

  1. class Solution { 
  2.     public List<Integer> preorderTraversal(TreeNode root) { 
  3.         List<Integer> result = new LinkedList<>(); 
  4.         Stack st = new Stack<>(); 
  5.         if (root != null) st.push(root); 
  6.         while (!st.empty()) { 
  7.             TreeNode node = st.peek(); 
  8.             if (node != null) { 
  9.                 st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中 
  10.                 if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈) 
  11.                 if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈) 
  12.                 st.push(node);                          // 添加中节点 
  13.                 st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。 
  14.                  
  15.             } else { // 只有遇到空节点的时候,才将下一个节点放进结果集 
  16.                 st.pop();           // 将空节点弹出 
  17.                 node = st.peek();    // 重新取出栈中元素 
  18.                 st.pop(); 
  19.                 result.add(node.val); // 加入到结果集 
  20.             } 
  21.         } 
  22.         return result; 
  23.     } 

迭代法中序遍历代码如下:

  1. class Solution { 
  2. public List<Integer> inorderTraversal(TreeNode root) { 
  3.         List<Integer> result = new LinkedList<>(); 
  4.     Stack st = new Stack<>(); 
  5.     if (root != null) st.push(root); 
  6.     while (!st.empty()) { 
  7.         TreeNode node = st.peek(); 
  8.         if (node != null) { 
  9.             st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中 
  10.             if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈) 
  11.             st.push(node);                          // 添加中节点 
  12.             st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。 
  13.  
  14.             if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈) 
  15.         } else { // 只有遇到空节点的时候,才将下一个节点放进结果集 
  16.             st.pop();           // 将空节点弹出 
  17.             node = st.peek();    // 重新取出栈中元素 
  18.             st.pop(); 
  19.             result.add(node.val); // 加入到结果集 
  20.         } 
  21.     } 
  22.     return result; 

迭代法后序遍历代码如下:

  1. class Solution { 
  2.    public List<Integer> postorderTraversal(TreeNode root) { 
  3.         List<Integer> result = new LinkedList<>(); 
  4.         Stack st = new Stack<>(); 
  5.         if (root != null) st.push(root); 
  6.         while (!st.empty()) { 
  7.             TreeNode node = st.peek(); 
  8.             if (node != null) { 
  9.                 st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中 
  10.                 st.push(node);                          // 添加中节点 
  11.                 st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。 
  12.                 if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈) 
  13.                 if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)          
  14.                                 
  15.             } else { // 只有遇到空节点的时候,才将下一个节点放进结果集 
  16.                 st.pop();           // 将空节点弹出 
  17.                 node = st.peek();    // 重新取出栈中元素 
  18.                 st.pop(); 
  19.                 result.add(node.val); // 加入到结果集 
  20.             } 
  21.         } 
  22.         return result; 
  23.    } 

Python:

迭代法前序遍历:

  1. class Solution: 
  2.     def preorderTraversal(self, root: TreeNode) -> List[int]: 
  3.         result = [] 
  4.         st= [] 
  5.         if root: 
  6.             st.append(root) 
  7.         while st: 
  8.             node = st.pop() 
  9.             if node != None: 
  10.                 if node.right: #右 
  11.                     st.append(node.right
  12.                 if node.left: #左 
  13.                     st.append(node.left
  14.                 st.append(node) #中 
  15.                 st.append(None) 
  16.             else
  17.                 node = st.pop() 
  18.                 result.append(node.val) 
  19.         return result 

迭代法中序遍历:

  1. class Solution: 
  2.     def inorderTraversal(self, root: TreeNode) -> List[int]: 
  3.         result = [] 
  4.         st = [] 
  5.         if root: 
  6.             st.append(root) 
  7.         while st: 
  8.             node = st.pop() 
  9.             if node != None: 
  10.                 if node.right: #添加右节点(空节点不入栈) 
  11.                     st.append(node.right
  12.                  
  13.                 st.append(node) #添加中节点 
  14.                 st.append(None) #中节点访问过,但是还没有处理,加入空节点做为标记。 
  15.                  
  16.                 if node.left: #添加左节点(空节点不入栈) 
  17.                     st.append(node.left
  18.             else: #只有遇到空节点的时候,才将下一个节点放进结果集 
  19.                 node = st.pop() #重新取出栈中元素 
  20.                 result.append(node.val) #加入到结果集 
  21.         return result 

迭代法后序遍历:

  1. class Solution: 
  2.     def postorderTraversal(self, root: TreeNode) -> List[int]: 
  3.         result = [] 
  4.         st = [] 
  5.         if root: 
  6.             st.append(root) 
  7.         while st: 
  8.             node = st.pop() 
  9.             if node != None: 
  10.                 st.append(node) #中 
  11.                 st.append(None) 
  12.                  
  13.                 if node.right: #右 
  14.                     st.append(node.right
  15.                 if node.left: #左 
  16.                     st.append(node.left
  17.             else
  18.                 node = st.pop() 
  19.                 result.append(node.val) 
  20.         return result 

旧文链接:二叉树:前中后序迭代方式的写法就不能统一一下么?

 

来源:代码随想录内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯