【待更新】
6. 树
6.1 树的结构
Terminology of Tree
Complete binary search tree完全二叉树
Binary Search Tree
满二叉树、完全二叉树无数值,从BST开始,internal nodes(非leaf node)包含数值。这里注意,node和左右节点的值可能相同。
AVL Tree
6.2 二叉树的储存方式
- 顺序储存 -> 按照parent -> left child -> right child -> left grandchild of left child -> right gradchild of left child… 的顺序储存在连续内存中 -> 以数组作为容器。
- 链式储存,每个node同时包含两指针,分别指向left child和right child,更常用。
6.3 二叉树的遍历方法
- 深度优先遍历
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法)
- 广度优先遍历
- 层次遍历(迭代法)
前中后序遍历的区别在于:中间节点的位置。
前序遍历(中左右):{10, 5, 1, 7, 40, 50}
中序遍历(左中右):{1, 5, 7, 10, 40, 50}
后序遍历(左右中):{1, 7, 5, 50, 40, 10}
10
/ \
5 40
/ \ \
1 7 50
6.4 Advantages of BST over HashTable
HashTable 在search, insert, delete操作中都能达到O(1),然而自平衡树BST(avl tree, res black tree等)需要O(logn). 除了Time Complexity之外,BST与HashTable的优越性体现在哪些情况下呢?
- BST中,中序遍历可以得到sorted结果in O(logn),在HashTable中不是natural operation需要extra effort.
- Doing order statistics, finding closest lower and greater elements, doing range queries are easy to do with BSTs
- BSTs are easy to implement compared to hashing. Libraries are needed when implementing hasing.
- With Self-Balancing BSTs, all operations are guaranteed to work in O(Logn) time. But with Hashing, Θ(1) is average time and some particular operations may be costly i.e, O(n2 ), especially when table resizing happens.
6.5 二叉树相关题目
6.5.1 Define a TreeNode 树节点的定义
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.rihgt = right;
}
}
6.5.2 BST Traversal 二叉树遍历
虽然以下分类是按照递归、迭代和层序遍历,但层序遍历是和前中后序遍历同级别,对遍历输出结果的要求;而递归和迭代是代码思路和书写方式,可分别应用于前中后及层序遍历。
6.5.2.1 Recursive Traserval 递归遍历
递归法 recursive, O(n), 节点个数
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
preOrder(res, root);
return res;
}
void preOrder(List<Integer> res, TreeNode root){
if (root == null) return;
res.add(root.val);
preOrder(res, root.left);
preOrder(res, root.right);
}
}
后序遍历类似,中序遍历在6.5.3,不多赘述。
6.5.2.2 Iterative Traserval 用栈迭代
递归那么简单,为什么要学其他方法?在实际项目开发的过程中我们是要尽量避免递归!因为项目代码参数、调用关系都比较复杂,不容易控制递归深度,甚至会栈溢出。
前序遍历
用栈实现:出栈顺序:中左右,入栈顺序中右左。
具体地,中 -> 出栈 -> 右入栈 -> 左入栈 -> 左出栈 -> 右出栈
class Solution{
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!.stack.isEmpty()){
TreeNode node = stack.pop();
res.append(node.val);