[LeetCode]二叉树层次遍历讲解与实例

来源:互联网 发布:matlab分水岭分割算法 编辑:程序博客网 时间:2024/06/15 20:16

[LeetCode]二叉树层次遍历讲解与实例

0.题目

leetcode : 199. Binary Tree Right Side View

1.题目描述

Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

For example:
Given the following binary tree,

   1            <--- /   \2     3         <--- \     \  5     4       <---

You should return [1, 3, 4].

2.题目分析

题目大意是让我们输出一棵二叉树每一层最右边的一个节点的数值。

我们一般是通过深度优先搜索(DFS)对二叉树进行遍历的,例如三种遍历方式:先序遍历,中序遍历,后序遍历,详细的讲解可以看这篇博客根据树的遍历还原树.
一般情况下,深度优先搜索是通过栈实现的,虽然我们在遍历的时候没有使用递归,看似没有使用栈,但是要记住递归也是通过栈实现,下面给大家一种普适的通过栈实现深度优先搜索的代码

    stack<int> DFS;    DFS.push(root);    while (DFS.size() != 0) {        // need pop first        DFS.pop();        DFS.push(DFS.top()->left);        DFS.push(DFS.top()->right);        // do something there    }

上面的代码只是例子,想让大家了解一下如何使用栈来实现深度优先搜索。
通过代码我们可以发现,我们将当前节点的左右子树push进栈,这是节点的值是在栈顶的。而每次我们访问的又恰好是栈顶的元素,这就保证了我们每次都是深度优先。大家最好自己模拟一下遍历过程,这样能更好的理解栈与深度优先搜索的关系。


解决本题使用深度优先搜索比较麻烦(大家可以自己尝试),所以我们要换一种思路–广度优先搜索。
题目要求我们输出每一层最右边的数,我们可以想一想,在广度优先搜索(BFS)的定义中,是不是也有这种的思想出现呢?广度优先搜索对于一个节点来说,先访问它的所有子节点,然后再访问子节点的子节点(深度优先搜索是顺着根节点先访问完这一条路径上的所有节点,然后再去访问第二个子节点),这是不是出现了
广度优先搜索是通过队列实现的,下面同样给出一个普适的通过队列实现广度优先搜索的例子

    queue<int> BFS;    BFS.push(root);    while (BFS.size() != 0) {        BFS.push(BFS.front()->left);        BFS.push(BFS.front()->right);        // do something there        BFS.pop();    }

同样的大家可以模拟一下代码执行的过程,对比深度优先搜索,这样能更好的理解队列、栈、广度优先搜索和深度优先搜索。


我们已经知道了怎样层次遍历,也就是说我们已经按遍历二叉树了,但是要想解决问题还有两个困难之处
1. 如何判断哪个节点位于哪一层呢?
2. 如果子节点是空的话按层次遍历不就会少两个数吗?

大家可以自己思考一下,解决方案我会在代码中说明。

3.代码实现

先看完整的代码

vector<int> rightSideView(TreeNode* root) {    queue<TreeNode* > BFS;    vector<int> result;    if (root == NULL)        return result;    int rightSide = 1;    int null = 0;    int index = 0;    BFS.push(root);    while (BFS.size() != 0) {        index++;        if (BFS.front()->left != NULL) {            BFS.push(BFS.front()->left);        } else {            null++;        }        if (BFS.front()->right != NULL) {            BFS.push(BFS.front()->right);        } else {            null++;        }        if (index == rightSide) {            result.push(BFS.front()->val);            rightSide = rightSide * 2 - null;            null = 0;        }        BFS.pop();    }    return result;}
  1. 对于二叉树,我们可以发现每一层节点数目都是上一层的两倍(每个根节点有两个子节点),所以我们可以用一个index来作为每个节点在每一层中的下标。
  2. 用null来记录每一层中null节点的数目
  3. 用rightSide记录每一层应该有多少节点(在删除空节点之后)。在没有空节点的时候,下一层的节点数应该是当前层节点数x2,我们知道当前层的节点数,double之后再减去下一层空节点的数目就是下一层应该有的节点数

我们可以发现,每次当index == rightSide时,证明我们到了最右端,到了最右端之后,我们需要重置index和null(从第一个开始算,并且新的一层空节点数暂时为0),此时我们就需要更新新一层的节点数,从第三点分析我们可以得到rightSide = rightSide * 2 - null。
其中的逻辑关系大家可以自己画图分析一下,这样更有助于理解。

4.结束

解题并不是关键,但是理解栈和深度优先搜索、队列和广度优先搜索的关系很重要。
模拟程序运行的步骤对于理解这两种重要的搜索方式有很大帮助。

对于任何我没有写清楚的地方请在评论区留言。

原创粉丝点击