- 一般遍历二叉树要么使用递归,要么借助于栈或队列。遍历的时间复杂度为O(n),空间复杂度也为O(n)
- 在LeetCode第99题Recover Binary Search Tree中,使用栈的解答较为简便:
// 中序遍历
public void recoverTreex(TreeNode root) {
if(root == null) return;
TreeNode prev = null, first = null, second = null;
Stack<TreeNode> stack = new Stack<>();
while(root != null || !stack.isEmpty()){
while(root!=null){
stack.push(root);
root = root.left;
}
root = stack.pop();
if(prev != null && root.val < prev.val){
if(first == null) first = prev; //存第一个反序对的前一个节点
second = root;//存第二个反序对的后一个节点
}
prev = root;
root = root.right;
}
int tmp = second.val;
second.val = first.val;
first.val = tmp;
}
-
Follow up:
A solution using O(n) space is pretty straight forward.
Could you devise a constant space solution?能否使用O(1)空间复杂度解决问题呢?——Morris中序遍历 -
Morris算法——以时间换空间
- 整个遍历过程都是按照二叉树递归遍历的思路进行。以时间换空间,对路径进行了重复的访问。
- 利用了叶子节点的空指针域,遍历过程,先利用空指针保存以后要到达的路径,
- 使用完成之后再恢复成空指针。
- 只是在输出节点信息(即访问节点信息)处有不同。
中序遍历保存节点
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> inorder = new ArrayList<>();
TreeNode pnode = root, tmp = null;
while(pnode != null){
if(pnode.left == null){
inorder.add(pnode.val);
pnode = pnode.right; //总是指向中序的下一个节点
} else{
tmp = pnode.left;
// 找到左子树的最右子节点
while(tmp.right != null && tmp.right != pnode)
tmp = tmp.right;
if(tmp.right == null){ //第一次遍历 == null
tmp.right = pnode; // 叶子节点的右孩子记录将要遍历的顺序
pnode = pnode.left;
} else{ //第二次遍历 == pnode
inorder.add(pnode.val);
tmp.right = null; //恢复为空节点
pnode = pnode.right;
}
}
}
return inorder;
}
99题解法
public void recoverTree(TreeNode pnode) {
if(pnode == null) return;
TreeNode prev = null, first = null, second = null;
TreeNode tmp = null;
while(pnode != null){
if(pnode.left == null){
if(prev != null && pnode.val < prev.val){
if(first == null) first = prev; //存第一个反序对的前一个节点
second = pnode;//存第二个反序对的后一个节点
}
prev = pnode;
pnode = pnode.right;
} else{
tmp = pnode.left;
// 找到左子树的最右子节点
while(tmp.right != null && tmp.right != pnode)
tmp = tmp.right;
if(tmp.right == null){ //第一次遍历 == null
tmp.right = pnode; // 叶子节点的右孩子记录将要遍历的顺序
pnode = pnode.left;
} else{
if(prev != null && pnode.val < prev.val){
if(first == null) first = prev; //存第一个反序对的前一个节点
second = pnode;//存第二个反序对的后一个节点
}
prev = pnode;
tmp.right = null; //恢复为空节点
pnode = pnode.right;
}
}
}
int temp = second.val;
second.val = first.val;
first.val = temp;
}