代码随想录day 14 - 树
二叉树理论基础
满二叉树
如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
完全二叉树
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
二叉搜索树
二叉搜索树是一个有序树。
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树
平衡二叉搜索树
又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉树的遍历方式
深度优先遍历:
广度优先遍历: 层次遍历
Java中二叉树的定义
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
二叉树的递归遍历
144. 二叉树的前序遍历
递归函数的参数和返回值:
因为要打印出前序遍历节点的数值,所以参数里需要传入list来放节点的数值,除了这一点就不需要再处理什么数据了也不需要有返回值,所以递归函数返回类型就是void
终止条件:
在递归的过程中,如果当前遍历的节点是空了,那么本层递归就结束了,直接return
单层递归的逻辑:
前序遍历是中左右的循序,所以在单层递归的逻辑,是要先取中节点的数值
完整代码如下:
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
preorder(root, list);
return list;
}
public void preorder(TreeNode root, List<Integer> list){
if(root == null) return;
list.add(root.val);//中
preorder(root.left, list);//左
preorder(root.right, list);//右
}
}
94. 二叉树的中序遍历
完整代码如下:
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
inorder(root, list);
return list;
}
public void inorder(TreeNode root, List<Integer> list){
if(root == null) return;
inorder(root.left, list); //左
list.add(root.val); 中
inorder(root.right, list); //右
}
}
145. 二叉树的后序遍历
完整代码如下:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
postorder(root, list);
return list;
}
public void postorder(TreeNode root, List<Integer> list){
if(root == null) return;
postorder(root.left, list); //左
postorder(root.right, list); //右
list.add(root.val); //中
}
}
二叉树的迭代遍历
144. 二叉树的前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
if(root == null) {
return list;
}
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
list.add(node.val); // 中
// 右(空节点不入栈)
if(node.right != null){
stack.push(node.right);
}
// 左(空节点不入栈)
if(node.left != null){
stack.push(node.left);
}
}
return list;
}
}
94. 二叉树的中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()){
// 指针来访问节点,访问到最底层
if(cur != null){
stack.push(cur); // 将访问的节点放进栈
cur = cur.left; // 左
}else{
cur = stack.pop(); // 从栈里弹出的数据,就是要处理的数据(放进list数组里的数据)
list.add(cur.val); // 中
cur = cur.right; // 右
}
}
return list;
}
}
中序遍历注意当cur为空时,stack.pop()
要设置为当前指针指向的节点cur,而不是重新设立一个TreeNode节点。
145. 二叉树的后序遍历
class Solution {
后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
public List<Integer> postorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
if(root == null){
return list;
}
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
list.add(node.val);
// 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
if(node.left != null){
stack.push(node.left);
}
if(node.right != null){
stack.push(node.right);
}
}
Collections.reverse(list);// 将结果反转之后就是左右中的顺序了
return list;
}
}