理论基础
- 概念:
- 满二叉树
- 定义:树只有度为0或度为2的节点。若深度为K,树有2^(K-1)个节点。
- 完全二叉树
- 定义:除了最底层节点可能没填满,其余每层节点数量都达到了最大值,且最下面那一层集中在左边的
- 延申:优先级队列就是一个堆,堆就是一棵完全二叉树。
- 二叉搜索树
- 定义:若子树不空,则左子树的点全小于根节点;同理右节点。
- 平衡二叉搜索树
- 定义:一颗空树或它左右俩子树的高度差绝对值不超过1,并且左右两个子树都是平衡二叉树。
- 满二叉树
- 代码:
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; } }
- 常用容器底层实现:
- Arraylist:底层由动态数组实现
- LinkedList:底层实现为双向链表,即每个元素都包含一个向前/向后的元素指针。
- HashSet:底层实现为哈希表
- LinkedHashSet:底层实现除了哈希表,还有一条双向链表。
- TreeSet:一种红黑树,一种平衡的二叉搜索树。
- HashMap:底层实现为哈希表
- LinkedHashMap:同理,多了一条双向链表
- PriorityQueue:由二叉堆(数组)实现。
递归遍历
- 递归三要素
- 确定递归函数的参数与返回值:确定哪些参数是递归过程中需要处理的,在递归函数里加入它们。并且要明确每次递归返回值是什么进而确定返回类型。
- 确定终止条件:确定终止条件保证栈不溢出。
- 确定单层递归逻辑:确定每一层递归需要处理的信息。
- 144. 二叉树的前序遍历 - 力扣(LeetCode)
- 思路: 前序遍历,即中间的node在前!
- 代码
class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); preOrder(root,result); return result; } public void preOrder(TreeNode root, List<Integer>result){ if(root == null){ return; } result.add(root.val); preOrder(root.left,result); preOrder(root.right,result); } }
- 94. 二叉树的中序遍历
- 思路: 中间的node在中间,即左中右
- 代码
lass Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); inOrder(root, result); return result; } public void inOrder(TreeNode root, List<Integer> result){ if(root == null){ return; } inOrder(root.left,result); result.add(root.val); inOrder(root.right,result); } }
- 145. 二叉树的后序遍历
- 思路: 中间的node在最后,即左右中。
- 代码
class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); postOrder(root,result); return result; } public void postOrder(TreeNode root, List<Integer> result){ if(root==null){ return; } postOrder(root.left,result); postOrder(root.right,result); result.add(root.val); } }
迭代遍历
- 144. 二叉树的前序遍历 - 力扣(LeetCode)
- 思路: 使用栈,每次pop出去将右、左node加入。直到栈再空。
- 前序:中左右
- 进栈:中右左
- 出栈:中左右
- 代码
class Solution { public List<Integer> preorderTraversal(TreeNode root) { //使用栈来解决 List<Integer> result = new ArrayList<>(); if(root==null){ return result; } Deque<TreeNode> stack = new ArrayDeque<>(); stack.offerLast(root); while(!stack.isEmpty()){ TreeNode tmp = stack.pollLast(); result.add(tmp.val); if(tmp.right!=null){ stack.offerLast(tmp.right); } if(tmp.left!=null){ stack.offerLast(tmp.left); } } return result; } }
- 思路: 使用栈,每次pop出去将右、左node加入。直到栈再空。
- 94. 二叉树的中序遍历
- 思路: 一个栈与一个指针配合。先左,左到底了就poll出最后一个元素,然后cur变为poll出元素的右子。
- 代码
class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); if (root == null){ return result; } Deque<TreeNode> stack = new ArrayDeque<>(); TreeNode cur = root; while(cur != null || !stack.isEmpty()){ if(cur!=null){ stack.offerLast(cur); cur = cur.left; }else{ cur = stack.pollLast(); result.add(cur.val); cur = cur.right; } } return result; } }
- 145. 二叉树的后序遍历
- 思路: 中间的node在最后,即左右中。
- 进栈:中左右
- 出栈:中右左
- 最后翻转:左右中
- 代码
class Solution { public List<Integer> postorderTraversal(TreeNode root) { //使用栈来解决 List<Integer> result = new ArrayList<>(); if (root==null){ return result; } Deque<TreeNode> stack = new ArrayDeque<>(); stack.offerLast(root); while(!stack.isEmpty()){ TreeNode tmp = stack.pollLast(); result.add(tmp.val); if(tmp.left!=null){ stack.offerLast(tmp.left); } if(tmp.right!=null){ stack.offerLast(tmp.right); } } //一个Collections类的静态方法 Collections.reverse(result); return result; } }
- 思路: 中间的node在最后,即左右中。