完全二叉树
除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。
在内存里位置连续,不会有unused gap。节省内存
平衡二叉搜索树
平衡二叉搜索树:又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
遍历方式
1. 深度优先遍历:先往深走,遇到叶子节点再往回走。
- 实现方法1: 递归遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<Integer>();
preorder(root, result);
return result;
}
public void preorder(TreeNode root, List<Integer> result) {
if (root == null) { // 记住终止条件是当前节点为null
return;
}
result.add(root.val);
preorder(root.left, result);
preorder(root.right, result);
}
}
-
实现方法2: 迭代遍历
前序遍历:需借用Stack,再把root点pop出去之前判断是否为空作为
循环条件
,然后弹出当前处理的节点,依次压入右、左节点。后序遍历:遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<Integer>();
Stack<TreeNode> stack = new Stack<>();
if (root == null) return result;
stack.push(root);
while (!stack.isEmpty()){ //迭代循环
TreeNode node = stack.pop();
result.add(node.val);
if (node.right != null){
stack.push(node.right);
}
if (node.left != null){
stack.push(node.left);
}
}
}
//遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if (node.left != null){
stack.push(node.left);
}
if (node.right != null){
stack.push(node.right);
}
}
Collections.reverse(result);
return result;
}
中历遍历: 先把左支全部压进栈,按顺序把左支节点放入result中,同时如果该节点有右支,指向右节点,刚好是左-中-右的顺序。
再加上指针,指向入栈的元素。一旦X的右为空,根据左中右的顺序,说明以X为根节点的子树都访问了,随即就要去弹出栈中下一个元素(如果还有元素的话)
// 中序遍历顺序: 左-中-右 入栈顺序: 左-右
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()){
// 左支全部压入,从下往上寻找节点是否有右枝。
if (cur != null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
}
return result;
}
}
2. BFS:层序遍历
光用二叉树这一数据结构无法做到BFS,需要借用Queue保存每一层中的元素。
While循环条件
:
-
全部处理完为 queue是否为空
-
每一层处理完条件为上一层的len个节点len--
public List<List<Integer>> resList = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrder(TreeNode root) {
checkFun02(root);
return resList;
}
//BFS--迭代方式--借助队列
public void checkFun02(TreeNode node) {
if (node == null) return;
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.offer(node);
while (!que.isEmpty()) {
List<Integer> itemList = new ArrayList<Integer>();
int len = que.size();
while (len > 0) {
TreeNode tmpNode = que.poll();
itemList.add(tmpNode.val);
if (tmpNode.left != null) que.offer(tmpNode.left);
if (tmpNode.right != null) que.offer(tmpNode.right);
len--;
}
resList.add(itemList);
}
}
}
复杂度分析
时间复杂度:O(n) 其中 n是二叉搜索树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n) 为递归过程中栈的开销,平均情况下为O(logn),最坏情况下树呈现链状,为O(n)。
求深度/高度
-
求某节点深度是求该节点到root node的距离
-
可以使用层序遍历来求深度,但是不能直接用层序遍历来求高度
- 求某节点高度是求该节点到叶子节点的距离
求二叉树的最大深度就是求根节点的高度。
深度是根节点从0或1一层层往下数,用前序遍历实现;高度相反,用后序遍历实现。
class Solution {
// 层序遍历
public int maxDepth(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> que = new LinkedList<>();
que.offer(root);
int depth = 0;
while (!que.isEmpty())
{
int len = que.size(); //当前层节点个数
while (len > 0)
{
TreeNode node = que.poll();
if (node.left != null) que.offer(node.left); //下一层
if (node.right != null) que.offer(node.right); //下一层
len--;
}
depth++;
}
return depth;
}
}
求二叉树的最小深度
class Solution {
/**
* 递归法,相比求MaxDepth要复杂点
* 因为最小深度是从根节点到最近**叶子节点**的最短路径上的节点数量
*/
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if (root.left == null) {
return rightDepth + 1;
}
if (root.right == null) {
return leftDepth + 1;
}
// 左右结点都不为null
return Math.min(leftDepth, rightDepth) + 1;
}
}
class Solution { // 迭代法,层序遍历
public int minDepth(TreeNode root){
if (root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int depth = 0;
while (!queue.isEmpty()){
int size = queue.size();
depth++;
TreeNode cur = null;
for (int i = 0; i < size; i++) {
cur = queue.poll();
//如果当前节点的左右孩子都为空,直接返回最小深度
if (cur.left == null && cur.right == null){
return depth;
}
if (cur.left != null) queue.offer(cur.left);
if (cur.right != null) queue.offer(cur.right);
}
}
return depth;
}
}