if (root.left != null){
inorderTraversal(root.left);
}
//节点不为空,将节点的值添加进列表中
list.add(root.val);
//判断此节点的右节点是否为空,如果不为空则将递归遍历此节点的右子树
if (root.right != null){
inorderTraversal(root.right);
}
//最后返回列表
return list;
}
}
* 后续遍历(LeetCode 145)
class Solution {
//声明列表
ArrayList list = new ArrayList<>();
public List postorderTraversal(TreeNode root) {
// 如果根节点为空,则直接返回空列表
if (root == null){
return new ArrayList<>();
}
//判断此节点的左节点是否为空,如果不为空则将递归遍历此节点的左子树
if (root.left != null){
postorderTraversal(root.left);
}
//判断此节点的右节点是否为空,如果不为空则将递归遍历此节点的右子树
if (root.right != null){
postorderTraversal(root.right);
}
//节点不为空,将节点的值添加进列表中
list.add(root.val);
//最后返回列表
return list;
}
}
我们通过观察发现,这代码怎么这么像,是的就是很像,他们唯一的区别就是`list.add(root.val);`代码的位置不一样,这行代码就代表文中的 **遍历(访问)**
下图中为前序遍历(**根**左右)
![](https://upload-images.jianshu.io/upload_images/24195226-86f2674a452f8fe2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
下图中为中序遍历(左**根**右)
![](https://upload-images.jianshu.io/upload_images/24195226-c2100f0b2760e563.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
下图中为后序遍历(左右**根**)
![](https://upload-images.jianshu.io/upload_images/24195226-a509256842c6f3f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## 二叉树非递归遍历
> * 用到栈(FILO 先进后出的特性)
> * 每段代码后,都有栈和其中元素的关系具体过程,建议静下心来慢慢看,有助于理解代码如何运行
* 前序遍历
class Solution {
List list = new ArrayList();
public List preorderTraversal(TreeNode root) {
//如果根节点为空,则直接返回空列表
if(root==null){
return new ArrayList();
}
//声明一个栈
Stack stack = new Stack<>();
//将节点入栈
stack.push(root);
//如果栈不为空
while (!stack.empty()){
//从栈弹出这个节点
TreeNode node = stack.pop();
//添加进列表中
list.add(node.val);
// 如果这个节点的右子节点不为空
if (node.right!=null){
// 将其入栈 因为栈是先进后出,所以先压栈右子节点 后出
stack.push(node.right);
}
// 如果这个节点的左子节点不为空
if (node.left!=null){
// 将其入栈 因为栈是先进后出,所以后压栈左子节点 先出
}
}
//返回列表
return list;
}
}
![](https://upload-images.jianshu.io/upload_images/24195226-17daca543ecb78fe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/24195226-cab510c23a144af5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 中序遍历
class Solution {
public List inorderTraversal(TreeNode root) {
//判断节点是否为空,为空的话直接返回空列表
if (root == null){
return new ArrayList();
}
//声明列表存储结果
List list = new ArrayList();
//声明一个栈
Stack stack = new Stack<>();
//当节点不为空或者栈不为空时
while (root != null || !stack.empty()){
//当节点不为空时
while (root != null){
//将节点压栈
stack.push(root);
//将节点指向其左子节点
root = root.left;
}
//如果栈不为空
if (!stack.empty()){
//将栈里元素弹出来
TreeNode node = stack.pop();
//添加进列表中
list.add(node.val);
//将节点指向其右子节点
root = node.right;
}
}
return list;
}
}
![](https://upload-images.jianshu.io/upload_images/24195226-0c3c44ad935b4ebd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/24195226-5029d7b51fc12ec6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 后序遍历
class Solution {
public List postorderTraversal(TreeNode root) {
// 如果根节点为空,则直接返回空列表
if (root == null){
return new ArrayList<>();
}
//声明列表
ArrayList list = new ArrayList<>();
//声明栈A
Stack stackA = new Stack();
//声明栈B
Stack stackB = new Stack();
//将次元素压入栈A
stackA.push(root);
//当栈A不为空时
while (!stackA.empty()){
//取出其中压入的元素
TreeNode node = stackA.pop();
//压入栈B中
stackB.push(node);
//当此节点左子节点不为空时
if (node.left != null){
//压入栈A
stackA.push(node.left);
}
//当此节点右子节点不为空时
if (node.right != null){
//压入栈A
stackA.push(node.right);
}
}
//当栈B不为空时
while (!stackB.empty()){
//取出其元素并且添加至列表中
TreeNode node = stackB.pop();
list.add(node.val);
}
//最后返回列表
return list;
}
}
![](https://upload-images.jianshu.io/upload_images/24195226-22219c751fa541cc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/24195226-ed02783ebb046cfe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## 二叉树层序遍历(BFS)
> * LeetCode 102 二叉树的层序遍历
> * 用到队列(FIFO 先进先出的特性)代码后有队列和其中元素的关系具体过程,建议静下心来慢慢看,有助于理解代码如何运行
class Solution {
public List<List> levelOrder(TreeNode root) {
if (root == null) {
return new ArrayList<List>();
}
// 声明一个列表存储每一行的数据
List<List> result = new ArrayList<>();
//声明一个队列
LinkedList queue = new LinkedList<>();
//如果根节点不为空,将其入队
queue.offer(root);
//当队列不为空时,代表队列里有数据
while (!queue.isEmpty()) {
//存储每一行的数据line
List line = new ArrayList();
//保存队列中现有数据的个数,这些就是要添加至每一行列表的值
int size = queue.size();
for (int i=0;i<size;i++){
//取出队列的节点 (FIFO 先进先出)
TreeNode node = queue.poll();
line.add(node.val);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
result.add(line);
}
return result;
}
}
![](https://upload-images.jianshu.io/upload_images/24195226-ae71237befb5fcea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## leetcode二叉树相关练习
* 我们看到了这里,对二叉树的前序(DFS)、中序、后序、递归/非递归以及层次遍历(BFS)都有了一定的了解(**如果上面的图都消化了的话**)
然后我们趁热打铁来几道leetcode题目试试手!(总体代码和上面只有稍微的改动,因为大致思想是一样的,把上面的内容都消化了的话就很简单啦)
* leetcode-257 二叉树的所有路径
class Solution {
public List binaryTreePaths(TreeNode root) {
if (root == null){
return new ArrayList<>();
}
ArrayList list = new ArrayList<>();
Stack stack = new Stack();
//这个栈存储路径,与上一个存储节点的栈一样的操作
Stack path = new Stack();
stack.push(root);
path.push(root.val+"");
while (!stack.empty()){
TreeNode node = stack.pop();
String p = path.pop();
//当是叶子节点的时候,此时栈中的路径即为一条完整的路径,可以加入到结果中
if (node.right == null && node.left == null ){
list.add§;
}
//如果右子节点不为空
if (node.right != null){
stack.push(node.right);
//将临时路径继续压栈
path.push(p+"->"+node.right.val);
}
//如果左子节点不为空
if (node.left != null){
stack.push(node.left);
//将临时路径继续压栈
path.push(p+"->"+node.left.val);
}
总结
谈到面试,其实说白了就是刷题刷题刷题,天天作死的刷。。。。。
为了准备这个“金三银四”的春招,狂刷一个月的题,狂补超多的漏洞知识,像这次美团面试问的算法、数据库、Redis、设计模式等这些题目都是我刷到过的
并且我也将自己刷的题全部整理成了PDF或者Word文档(含详细答案解析),有需要的朋友可以戳这里即可免费领取
66个Java面试知识点
架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)
算法刷题(PDF)
自己刷的题全部整理成了PDF或者Word文档(含详细答案解析),有需要的朋友可以戳这里即可免费领取**
[外链图片转存中…(img-ulqTSdSp-1628229528402)]
66个Java面试知识点
架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)
[外链图片转存中…(img-x4YuEC7F-1628229528405)]
算法刷题(PDF)