Morris遍历

Morris遍历介绍与应用

Morris遍历是一种二叉树遍历方法,通过改写指针来实现无额外空间复杂度的遍历。

Morris遍历适用于内存紧张的环境,如嵌入式编程和系统编程,以减少空间占用。

Morris遍历的核心在于利用节点上的空闲指针,通过巧妙地改变指针指向来实现遍历。

时间复杂度为O(n),空间复杂度为O(1)

 

Morris实现代码

	public static void morris(Node head) {
		if (head == null) {
			return;
		}
		Node cur = head;
		Node mostRight = null;
		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;
				}
			}
			cur = cur.right;
		}
	}

 前序遍历

  1. 从根节点开始,如果当前节点未被访问,检查其是否有左子节点。
  2. 如果当前节点没有左子节点,访问当前节点,然后转向其右子节点。
  3. 如果当前节点有左子节点,找到左子树中的最右节点(即左子树的“前序遍历的最后一个节点”),这个节点称为“前驱节点”。
  4. 如果前驱节点的右子节点为空,将当前节点链接到前驱节点的右子节点上,并将当前节点标记为已访问,然后转向当前节点的左子节点。
  5. 如果前驱节点的右子节点是当前节点,说明当前节点已经被访问过,那么断开这个链接,访问当前节点,然后转向当前节点的右子节点。
  6. 重复步骤1-5,直到所有节点都被访问。
public static void morrisPre(Node head) {
		if (head == null) {
			return;
		}
		Node cur = head;
		Node mostRight = null;
		while (cur != null) {
			mostRight = cur.left;
			if (mostRight != null) {
				while (mostRight.right != null && mostRight.right != cur) {
					mostRight = mostRight.right;
				}
				if (mostRight.right == null) {
					System.out.print(cur.value + " ");
					mostRight.right = cur;
					cur = cur.left;
					continue;
				} else {
					mostRight.right = null;
				}
			} else {
				System.out.print(cur.value + " ");
			}
			cur = cur.right;
		}
		System.out.println();
	}

中序遍历

  1. 从根节点开始,如果当前节点未被访问,检查其是否有左子节点。
  2. 如果当前节点没有左子节点,访问当前节点,然后转向其右子树。
  3. 如果当前节点有左子节点,找到左子树中的最右节点(即左子树中最后一个被中序遍历的节点),这个节点称为“前驱节点”。
  4. 如果前驱节点的右子节点为空,将当前节点链接到前驱节点的右子节点上,并将当前节点标记为已访问,然后转向当前节点的左子树。
  5. 如果前驱节点的右子节点是当前节点,说明当前节点已经被访问过,那么断开这个链接,访问当前节点,然后转向当前节点的右子树。
  6. 重复步骤1-5,直到所有节点都被访问。
public static void morrisIn(Node head) {
		if (head == null) {
			return;
		}
		Node cur = head;
		Node mostRight = null;
		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;
				}
			}
			System.out.print(cur.value + " ");
			cur = cur.right;
		}
		System.out.println();
	}

 后序遍历

  • 首先检查头节点 head 是否为空,如果为空则直接返回。
  • 使用一个 cur 指针遍历树,同时使用 mostRight 指针找到 cur 左子树中的最右节点。
  • 如果 mostRight 的右指针为空,将其指向 cur,然后移动 cur 到其左子树。
  • 如果 mostRight 的右指针已经指向 cur,则说明已经访问过 cur 的左子树,此时将 mostRight 的右指针设为 null,打印从 cur 左子树到 cur 的边,然后继续遍历到 cur 的右子树。
  • 最后,打印从 head 到树的最右节点的边。
public static void morrisPos(Node head) {
		if (head == null) {
			return;
		}
		Node cur = head;
		Node mostRight = null;
		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;
					printEdge(cur.left);
				}
			}
			cur = cur.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;
	}

给定一棵二叉树的头结点head,求以head为头的树中,最小深度是多少?

递归法

public static class Node {
		public int val;
		public Node left;
		public Node right;

		public Node(int x) {
			val = x;
		}
	}

	public static int minHeight1(Node head) {
		if (head == null) {
			return 0;
		}
		return p(head);
	}

	// 返回x为头的树,最小深度是多少
	public static int p(Node x) {
		if (x.left == null && x.right == null) {
			return 1;
		}
		// 左右子树起码有一个不为空
		int leftH = Integer.MAX_VALUE;
		if (x.left != null) {
			leftH = p(x.left);
		}
		int rightH = Integer.MAX_VALUE;
		if (x.right != null) {
			rightH = p(x.right);
		}
		return 1 + Math.min(leftH, rightH);
	}

Morris法

// 根据morris遍历改写
	public static int minHeight2(Node head) {
		if (head == null) {
			return 0;
		}
		Node cur = head;
		Node mostRight = null;
		int curLevel = 0;
		int minHeight = Integer.MAX_VALUE;
		while (cur != null) {
			mostRight = cur.left;
			if (mostRight != null) {
				int rightBoardSize = 1;
				while (mostRight.right != null && mostRight.right != cur) {
					rightBoardSize++;
					mostRight = mostRight.right;
				}
				if (mostRight.right == null) { // 第一次到达
					curLevel++;
					mostRight.right = cur;
					cur = cur.left;
					continue;
				} else { // 第二次到达
					if (mostRight.left == null) {
						minHeight = Math.min(minHeight, curLevel);
					}
					curLevel -= rightBoardSize;
					mostRight.right = null;
				}
			} else { // 只有一次到达
				curLevel++;
			}
			cur = cur.right;
		}
		int finalRight = 1;
		cur = head;
		while (cur.right != null) {
			finalRight++;
			cur = cur.right;
		}
		if (cur.left == null && cur.right == null) {
			minHeight = Math.min(minHeight, finalRight);
		}
		return minHeight;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值