二叉树遍历(6 道 LeetCode 题目)

Posted 超越技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树遍历(6 道 LeetCode 题目)相关的知识,希望对你有一定的参考价值。

Hi,大家好,我是 Lefe,目前在做图解数据结构与算法,希望用图的方式让数据结构和算法变得通俗易懂,欢迎加入一起学习。

今天通过 6 道 LeetCode 题目学习「二叉树」这种数据结构的遍历。先看一下,什么是二叉树:

每个节点最多有 2 个子节点的树。


下图是一个二叉树:

叶子节点:没子节点的节点。


数据结构定义:

struct TreeNode {    // 值    int val;    // 左子树    TreeNode *left;    // 右子树    TreeNode *right;    TreeNode(int x) : val(x), left(NULL), right(NULL) {}};



LeetCode 上关于遍历的题目

94. Binary Tree Inorder Traversal 中序遍历

依次执行遍历左子树、访问值、遍历右子树。使用递归的方式实现,把结果保存到 vector 中:

class LEFTreeSubject {public: vector<int> result; vector<int> inorderTraversal(TreeNode* root) {        // 递归出口 if (root == NULL) { return result; } // 递归遍历左子树 inorderTraversal(root->left);        // 把遍历到的值保存到 result 中 result.push_back(root->val); // 递归遍历右子树 inorderTraversal(root->right); return result; }};


144. Binary Tree Preorder Traversal 前序遍历

依次执行访问值、遍历左子树、遍历右子树。使用递归的方式实现,把结果保存到 vector 中:

vector<int> preorderTraversal(TreeNode* root) { if (root == NULL) { return result; } result.push_back(root->val); // 递归遍历左子树 preorderTraversal(root->left); // 递归遍历右子树 preorderTraversal(root->right); return result;}


145. Binary Tree Postorder Traversal 后续遍历

依次执行遍历左子树、遍历右子树、访问值使用递归的方式实现,把结果保存到 vector 中:

vector<int> postorderTraversal(TreeNode* root) { if (root == NULL) { return result; } // 递归遍历左子树 postorderTraversal(root->left); // 递归遍历右子树 postorderTraversal(root->right); result.push_back(root->val); return result;}


102. Binary Tree Level Order Traversal 层序遍历

层序遍历是一种广度优先遍历算法,一层一层进行遍历,需要借助队列。每层结束位置用 NULL 分割。

vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> levelResult; // 用来暂存数据 queue<TreeNode *> q;  if (root == NULL) { return levelResult; } // 先存储根节点,每一层的结束用 NULL 分割 q.push(root); q.push(NULL); // 当前层的节点 vector<int> cur_vec; while (!q.empty()) { TreeNode *cur = q.front(); q.pop(); if (cur == NULL) { // 一层遍历结束了 levelResult.push_back(cur_vec); // 重置 cur_vec cur_vec.resize(0); if (q.size() > 0) { // 插入层的分割 q.push(NULL); } } else { cur_vec.push_back(cur->val); // 当前节点的左右节点入队 if (cur->left) { q.push(cur->left); } if (cur->right) { q.push(cur->right); } } }  return levelResult;}

107. Binary Tree Level Order Traversal II 层序遍历,从低向上遍历

题目要求从层序遍历相反的方向遍历,也就是从底向上遍历。这道题直接把 102 道题中的第 19 行代码(投机取巧):

 levelResult.push_back(cur_vec);

 改为:

 levelResult.insert(levelResult.begin(), cur_vec);

103. Binary Tree Zigzag Level Order Traversal 之字形层序遍历

这道题是层序遍历的扩展,它要求先左遍历,再右遍历,再左遍历,再右遍历...... 依次遍历。其实稍微对层序遍历(102)改一下就可以,增加一个标记位 isLeft 记录当前遍历的方向即可。

// 之字形遍历vector<vector<int>> zigzagLevelOrder(TreeNode* root) { vector<vector<int>> levelResult; // 用来暂存数据 queue<TreeNode *> q;  if (root == NULL) { return levelResult; } // 先存储根节点,每一层的结束用 NULL 分割 q.push(root); q.push(NULL); // 当前层的节点 vector<int> cur_vec; bool isLeft = true; while (!q.empty()) { TreeNode *cur = q.front(); q.pop(); if (cur == NULL) { // 一层遍历结束了 levelResult.push_back(cur_vec); // 重置 cur_vec cur_vec.resize(0); if (q.size() > 0) { // 插入层的分割 q.push(NULL); isLeft = !isLeft; } } else { if (isLeft) { cur_vec.push_back(cur->val); } else { cur_vec.insert(cur_vec.begin(), cur->val); } // 当前节点的左右节点入队 if (cur->left) { q.push(cur->left); } if (cur->right) { q.push(cur->right); } } }  return levelResult;}


二叉树的遍历有前、中、后序遍历,层序遍历。其中前 3 中使用递归的方式实现比较简单,当然也可以使用非递归的方式,可以借助「栈」来实现。层序遍历使用了非递归实现,借助于队列,其实它是一种广度优先算法。

如果你对下面这种递归实现,脑补不到代码的执行顺序,比如第 6、8、9 行代码的执行顺序是什么?是执行完第 6 行,然后紧接着执行第 8行?如果你心中有疑惑,对代码执行顺序模棱两可,下一篇文章,我保证把这些问题将明白了。「图解递归」

vector<int> postorderTraversal(TreeNode* root) { if (root == NULL) {            return result; } // 递归遍历左子树 postorderTraversal(root->left); // 递归遍历右子树 postorderTraversal(root->right); result.push_back(root->val); return result;}


推荐阅读:



图解数据结构和算法



以上是关于二叉树遍历(6 道 LeetCode 题目)的主要内容,如果未能解决你的问题,请参考以下文章

二叉树3. 层次遍历之二:3道变形题目

11道精选经典LeetCode例题让你彻底搞懂二叉树的广度优先遍历

二叉树构建与遍历-LeetCode 103108109(二叉树的构建,层次遍历)

LeetCode-面试算法经典-Java实现106-Construct Binary Tree from Inorder and Postorder Traversal(构造二叉树II)(示例(代码片

p34 二叉树的后续遍历 (leetcode 145)

p32 二叉树的前序遍历 (leetcode 144)