Binary Tree
General Tree
又向,联通,无环
class TreeNode {
int key;
List<TreeNode> children;
public TreeNode(int key) {
this.key = key;
children = new ArrayList<TreeNode>();
}
}
root //拎出来root就找到了整个树General Graph
class GraphNode {
int key;
List<TreeNode> neighbors;
public GraphNode(int key) {
this.key = key;
neighbors = new ArrayList<GraphNode>();
}
}
List<GraphNode> //因为这个时候不能用一个root拎出来整张图了,需要一个list of node
//or adjacency list
//or adjacency matrixA的neighbor里有B说明A到B有边,但是只有查了B才能知道B到A有没有边(对于有向图)
G = V + E
Given V, Dense Graph的E是O( ), Sparse Graph的E是O(v). 矩阵只适合node少的情况(sparse graph),而list适合node多的情况。

如果简化adj list,用list of list,这个list可以是array list, 也可以是linked list. 把vertex的index存下来,那么就可以用graph.get(i)拿到第i个node的 neighbor index 做算法题的时候,都是下面这种简化的。在实际工作中其实还是哟搞得上面的general graph,因为需要有value在
外层list的顺序重要,里面的list的数量无所谓
Iterative Traversal of Binary Tree
why iterative?
from stack to heap
for iterators
Pre-Order
root进,pop栈顶并打印,右进,左进,pop栈顶并打印... 直到栈空了 因为stack是先进后出,所以进stack时先进右后进左
Time: O(n) Space: heap上的那堆右节点 O(height)
In-Order
关键是要知道什么时候左子树被打印完了 用一个helper,when helper is null, it means the left subtree of the root is finished, the root is the top element in the stack 当helper是null的时候,当前的左都打完了,这个时候可以放右边的node进helper;最后栈空了,但是helper不是null,这个时候就可以pop打印了。
helper的意义:下一个要看的节点 如果不是null就入栈 如果是null就证明当前栈的top(左边)被打印完了,可以pop了,pop完helper里是刚才pop的节点的 right child 直到left和right都是空的时候停止
Post-Order
奇技淫巧 反过来pre-order
Time: O(2n) Space: O(n)
正派做法 记录从哪里来的
如果prev是current的parent,这是第一次看到它;如果prev是current的left child,这是第二次看到它;如果prev是curr的right child,可以打印了
root = stack.top
if previous is null --> going down (left subtree)
if previous is current's parent --> going down (left subtree)
go down: 有左,优先左;没有左,打印右; 都没有,打印自己并弹栈 from left: 右或者打印自己并弹栈 from right: 打印自己并弹栈 偷看栈顶 从上下来,有左压左,有右压右,左右都无,打印自己 从左上来,有右压右,无右打自己 从右上来,打印自己
Binary Search Tree
对任何一个节点,左边的所有数都比它小,右边所有都比它大 优势是search时每一步砍掉一半的子树,缩小搜索空间。
search() worst case O(n) average(logn)
insert() worst case O(n) average(logn)
remove() worst case O(n) average(logn)
Self-Balancing Binary Search Tree
为了解决BST不总是平衡的问题,有了两种特殊的树,自己维持self-balancing的状态,以保证以上三种操作的时间复杂度都是logn
AVL Tree
Red-Black Tree
Red-Black Tree
in Java: TreeMap / TreeSet
in C++: map/set
问题来了,重复node?那么就在Map里存一个value,也就是节点的数量。
Search in BST
Tail Recursion
最后一步且仅在最后一步调用自身 这种递归很容易写成iterative 这个写法的好处是先前存的所有stack都弹栈了。如果写成tail recursion的话 建议改写成iteration。
下面这个不是tail recursion,因为line 6这一行还在栈里。
return isBST()&&isBST()也不是tail recursion 因为最后一步是&&
另一个例子是求阶乘
Insert in BST
应该return改了的tree的root node
Delete in BST
leaf: 3.right=null
only has child on one sight: 3.right = 3.right.right / 3.right = 3.right.left
has children on both sides: 调右子树的最小值
如果右节点没有children 它自己就是最小的 然后把该继承的(原来的left)都继承好
如果右节点还有左子树 一直往左走,直到没有left为止 把最小的替换了 把最小的右子树接到原来的最小值位置
Time: O(height) Space: O(height)
Last updated