Morris算法简述:
遍历到每一个节点的时候,
1、如果当前节点有左孩子,则将当前节点做孩子的最右孩子指向自己;
2、如果当前节点没有左孩子,则跳向右边孩子;
3、如果当前节点左孩子最右节点指向自己,则断开,跳向下一个节点
public static void morris(TreeNode head){
if (head==null) return;
TreeNode cur=head;
TreeNode MostRightNode;
while(cur!=null){
MostRightNode=cur.left;
if (MostRightNode!=null){
//找到左孩子最右边孩子
while(MostRightNode.right!=null&&MostRightNode.right!=cur){
MostRightNode=MostRightNode.right;
}
if (MostRightNode.right==null){
//如果有左孩子,且第一次遍历会到这个地方
MostRightNode.right=cur;
cur=cur.left;
continue;
}else {
//如果有左孩子,且第二次遍历会到这个地方
MostRightNode.right=null;
}
}
//没有左孩子或者是第二次到达当前节点都会到这个地方
cur=cur.right;
}
}
以当前树为例子
遍历顺序就是ABDBEAC,有左孩子的节点都会遍历两遍
所以前序遍历就是当第一次到达当前节点的时候进行打印。
中序遍历就是当第二次遍历当前节点的时候进行打印
后序遍历比较麻烦,当第二次遍历当前节点的时候,需要将左孩子的节点逆序打印,如下面
最后将根节点右边逆序打印
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<Integer> ans = new LinkedList<>();
if(root==null)return ans;
// LinkedList<TreeNode> stack = new LinkedList<>();
// LinkedList<TreeNode> stack1 = new LinkedList<>();
// stack.push(root);
// while(!stack.isEmpty()){
// TreeNode cur=stack.pop();
// stack1.push(cur);
// if(cur.right!=null){
// stack.push(cur.right);
// }
// if(cur.left!=null){
// stack.push(cur.left);
// }
// }
// while(!stack1.isEmpty()){
// ans.add(stack1.pop().val);
// }
// return ans;
//morris
TreeNode cur=root;
while(cur!=null){
//先找到左孩子最右节点
TreeNode mostRightNode=cur.left;
if(mostRightNode!=null){
while(mostRightNode.right!=null&&mostRightNode.right!=cur){
mostRightNode=mostRightNode.right;
}
if(mostRightNode.right==null){
//第一次到达当前节点
mostRightNode.right=cur;
cur=cur.left;
continue;
}
if(mostRightNode.right==cur){
//第二次到达当前节点
mostRightNode.right=null;
print(cur.left,ans);
}
}
cur=cur.right;
}
print(root,ans);
return ans;
}
private static void print(TreeNode node,LinkedList<Integer> ans){
TreeNode newHead = reverse(node);
TreeNode point=newHead;
while (point!=null){
ans.add(point.val);
point=point.right;
}
reverse(newHead);
}
private static TreeNode reverse(TreeNode head){
TreeNode newHead=head;
TreeNode point;
while (head.right!=null){
point=head.right;
head.right=point.right;
point.right=newHead;
newHead=point;
}
return newHead;
}
是否是BST
以上面的树为例,当第二次来到当前节点的时候左树的所有节点已经遍历过了,此时因为是从左孩子最右节点指过来的,所以上一个节点代表的是左孩子上最大的值,如果是一个普通的没有左孩子的节点或者是叶子的话,遍历顺序都是右边,所以右边一定要比上一个节点更大。
public static boolean isBST(Node head) {
if (head == null) {
return true;
}
Node cur = head;
Node mostRight = null;
Integer pre = null;
boolean ans = true;
while (cur != null) {
mostRight = cur.left;
if (mostRight != null) {
while (mostRight.right != null && mostRight.right != cur) {
mostRight = mostRight.right;
}
if (mostRight.right == null) {
mostRight.right = cur;
cur = cur.left;
continue;
} else {
mostRight.right = null;
}
}
//当每次遍历到叶子节点或者是第二次来到当前节点,都需要判断当前节点是不是比上次保留的值大。
if (pre != null && pre >= cur.value) {
ans = false;
}
pre = cur.value;
cur = cur.right;
}
return ans;
}