遍历
前序遍历(深度优先遍历(DFS))
根在前,从左往右,一棵树的根永远在左子树前面,左子树又永远在右子树前面
ArrayList<TreeNode>list=new ArrayList<>();
void pre_order(TreeNode root)//前序遍历递归算法
{
if(Node == NULL)
return;
list.add(root);//显示节点数据,可以更改为其他操作。在前面
pre_order(root.left);
pre_order(root.right);
}
中序遍历
根在中,从左往右,一棵树的左子树永远在根前面,根永远在右子树前面
ArrayList<TreeNode>list=new ArrayList<>();
void pre_order(TreeNode root)//中序遍历递归算法
{
if(Node == NULL)
return;
pre_order(root.left);
list.add(root);//显示节点数据,可以更改为其他操作。
pre_order(root.right);
}
后续遍历
根在后,从左往右,一棵树的左子树永远在右子树前面,右子树永远在根前面
ArrayList<TreeNode>list=new ArrayList<>();
void pre_order(TreeNode root)//后序遍历递归算法
{
if(Node == NULL)
return;
pre_order(root.left);
pre_order(root.right);
list.add(root);//显示节点数据,可以更改为其他操作。
}
广度优先(BFS)
即层次遍历
public List<Integer> bfs(TreeNode root) {
//队列,用于中间的过程数据的存放
Queue<TreeNode> queue = new LinkedList<TreeNode>();
//链表,用于存放最终的结果
List<Integer> list=new LinkedList<Integer>();
//判断根节点是否为空
if(root==null)
return list;
//若不为空,就将头节点加入到队列中
queue.add(root);
//当队列不为空时(即队列中的数据未完全保存到链表中)
while (!queue.isEmpty()){
//将队列中第一个元素取出放入链表中,并将其子节点加入到队列中。(先左后右)
int sz=queue.size()
for (int i =0 ; i<sz;i++){
TreeNode t=queue.remove();
每步的操作
if(t.left!=null)
queue.add(t.left);
if(t.right!=null)
queue.add(t.right);
}
每层结束的操作
}
return list;
}
思维
拿到一个二叉树问题,首先问自己两个问题:
1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。
2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。
例如:计算二叉树最大深度
1、遍历的思维
// 记录最大深度
int res = 0;
// 记录遍历到的节点的深度
int depth = 0;
// 主函数
int maxDepth(TreeNode root) {
traverse(root);
return res;
}
// 二叉树遍历框架
void traverse(TreeNode root) {
if (root == null) {
return;
}
// 前序位置
depth++;
if (root.left == null && root.right == null) {
// 到达叶子节点,更新最大深度
res = Math.max(res, depth);
}
traverse(root.left);
traverse(root.right);
// 后序位置
depth--;
}
2、 分解问题
对于递归的问题,要学会下定义。
学会跳出代码看问题,充分利用定义而不是去理清楚递归的步骤。
// 定义:输入根节点,返回这棵二叉树的最大深度
int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
// 利用定义,计算左右子树的最大深度
int leftMax = maxDepth(root.left);
int rightMax = maxDepth(root.right);
// 整棵树的最大深度等于左右子树的最大深度取最大值,
// 然后再加上根节点自己
int res = Math.max(leftMax, rightMax) + 1;
return res;
}