Java实现Morris遍历二叉树

来源:互联网 发布:淘宝送手机充值卡 编辑:程序博客网 时间:2024/06/11 03:21

Morris遍历二叉树是遍历二叉树的神级方法,它的时间复杂度仅为O(n),空间复杂度为O(1)。

主要包含以下两大步骤:

1、拿到一个节点,如果该节点无左子树,那么节点指向它的右节点。

2、如果这个节点有左子树,找到左子树的最右节点。

       a、如果最右节点指向null,则让最右节点指向当前节点,并将该目标节点向左孩子移动。

       b、如果最右节点已经指向该节点,则让最右节点指向null,并将该目标节点向右孩子移动。

一直按照上述两大步骤递归,直到遍历完所有节点。

代码如下所示:

package problems_2017_08_21;/** * @author islongfei * 遍历二叉树的神级方法      【题目】       给定一棵二叉树的头节点head,完成二叉树的先序、中序和后序遍历。如果二叉树的节点数为N,       要求时间复杂度为O(N),额外空间复杂度为O(1)。 * */public class Problem_01_MorrisTraversal {public static class Node {public int value;Node left;Node right;public Node(int data) {this.value = data;}}/** * Morris 先序遍历二叉树(第一次发现节点就打印:①左子树的右孩子为空时打印 ②无左子树时打印) * @param head */public static void morrisPre(Node head) {if (head == null) {return;}Node cur1 = head;//每次得到的当前nodeNode cur2 = null;//当前node左子树最右的节点while (cur1 != null) {cur2 = cur1.left;if (cur2 != null) {while (cur2.right != null && cur2.right != cur1) {//找到左子树最右节点cur2 = cur2.right;}if (cur2.right == null) {   //最右点的右指针指向null,cur2.right = cur1;      //右指针指向当前节点System.out.print(cur1.value + " ");cur1 = cur1.left;       //当前node向左孩子移动continue;} else {                    //最右点的右指针已经指向当前节点,让它指向nullcur2.right = null;}} else {System.out.print(cur1.value + " ");}cur1 = cur1.right;              //当前node向右孩子移动}System.out.println();}/** * Morris中序遍历二叉树(node每次往右移之前打印节点) * @param head */public static void morrisIn(Node head) {if (head == null) {return;}Node cur1 = head;Node cur2 = null;while (cur1 != null) {cur2 = cur1.left;if (cur2 != null) {while (cur2.right != null && cur2.right != cur1) {cur2 = cur2.right;}if (cur2.right == null) {cur2.right = cur1;cur1 = cur1.left;continue;} else {cur2.right = null;}}System.out.print(cur1.value + " ");cur1 = cur1.right;}System.out.println();}/** * Morris后序遍历二叉树(当第二次回到node时,逆序打印左子树的右边界,在打印整树的右边界) * @param head */public static void morrisPos(Node head) {if (head == null) {return;}Node cur1 = head;Node cur2 = null;while (cur1 != null) {cur2 = cur1.left;if (cur2 != null) {while (cur2.right != null && cur2.right != cur1) {cur2 = cur2.right;}if (cur2.right == null) {cur2.right = cur1;cur1 = cur1.left;continue;} else {cur2.right = null;printEdge(cur1.left);}}cur1 = cur1.right;}printEdge(head);System.out.println();}public static void printEdge(Node head) {Node tail = reverseEdge(head);Node cur = tail;while (cur != null) {System.out.print(cur.value + " ");cur = cur.right;}reverseEdge(tail);}public static Node reverseEdge(Node from) {Node pre = null;Node next = null;while (from != null) {next = from.right;from.right = pre;pre = from;from = next;}return pre;}// for test -- print treepublic static void printTree(Node head) {System.out.println("Binary Tree:");printInOrder(head, 0, "H", 17);System.out.println();}public static void printInOrder(Node head, int height, String to, int len) {if (head == null) {return;}printInOrder(head.right, height + 1, "v", len);String val = to + head.value + to;int lenM = val.length();int lenL = (len - lenM) / 2;int lenR = len - lenM - lenL;val = getSpace(lenL) + val + getSpace(lenR);System.out.println(getSpace(height * len) + val);printInOrder(head.left, height + 1, "^", len);}public static String getSpace(int num) {String space = " ";StringBuffer buf = new StringBuffer("");for (int i = 0; i < num; i++) {buf.append(space);}return buf.toString();}public static void main(String[] args) {Node head = new Node(4);head.left = new Node(2);head.right = new Node(6);head.left.left = new Node(1);head.left.right = new Node(3);head.right.left = new Node(5);head.right.right = new Node(7);printTree(head);morrisPre(head);morrisIn(head);morrisPos(head);printTree(head);}}



根据打印的位置不同可以分为以下三种输出的遍历方法:

中序遍历:将目标节点往右移之前打印该节点。

先序遍历:第一次发现节点是就打印(1、左子树右孩子为空时 2、无左子树时)。

后续遍历:第二次回到目标节点,逆序打印左子树的右边界,再去打印整个树的右边界。


原创粉丝点击