算法与数据结构面试题(18)-二叉树镜像

题目


输入一颗二元查找树,将该树转换为它的镜像,
即在转换后的二元查找树中,左子树的结点都大于右子树的结点。
用递归和循环两种方法完成树的镜像转换。




解题思路


递归遍历每个结点,然后转换左右结点。


代码


前人写的二叉树java类,直接拿过来用。但是它的中序和后续的遍历代码调用了前序的代码,需要修改下。


/**
 * 二叉树的二叉链表表示
 */
public class BinaryTree<T> {

	private TreeNode root; // 根节点

	public BinaryTree() {
	}

	public BinaryTree(TreeNode root) {
		this.root = root;
	}

	/**
	 * 定义节点 内部类
	 */
	private static class TreeNode<T> {
		private T data = null; // 数据部分
		private TreeNode lchild; // 左节点的引用
		private TreeNode rchild; // 右节点的引用

		protected TreeNode() {
		}

		protected TreeNode(T data, TreeNode lchild, TreeNode rchild) {
			this.data = data;
			this.lchild = lchild;
			this.rchild = rchild;
		}

		private T getData() {
			return data;
		}

		private void setData(T data) {
			this.data = data;
		}

		private TreeNode getLchild() {
			return lchild;
		}

		private void setLchild(TreeNode lchild) {
			this.lchild = lchild;
		}

		private TreeNode getRchild() {
			return rchild;
		}

		private void setRchild(TreeNode rchild) {
			this.rchild = rchild;
		}
	}

	/**
	 * 返回父结点
	 *
	 * @param element
	 * @return
	 */
	public TreeNode getParent(TreeNode element) {
		// 如果传入参数为根节点或根节点为空,返回null
		return (root == null || root == element) ? null : parent(root, element);
	}

	/**
	 * @param subTree
	 * @param element
	 * @return
	 */
	public TreeNode parent(TreeNode subTree, TreeNode element) {
		if (subTree == null) {
			return null;
		}

		// 如果subTree的左孩子节点或右孩子节点等于element,则返回subTree
		if (subTree.getLchild() == element || subTree.getRchild() == element) {
			// 返回父结点地址
			return subTree;
		}

		TreeNode p;
		// 现在左子树中找,如果左子树中没有找到,才到右子树去找
		if ((p = parent(subTree.getLchild(), element)) != null) {
			// 递归在左子树中搜索
			return p;
		} else {
			// 递归在右子树中搜索
			return parent(subTree.getRchild(), element);
		}
	}

	/**
	 * 节点个数
	 *
	 * @return
	 */
	public int getSize() {
		return getNum(root);
	}

	private int getNum(TreeNode node) {
		if (node == null) {
			return 0;
		} else {
			int i = getNum(node.getLchild());
			int j = getNum(node.getRchild());
			return j + i + 1;
		}
	}

	/**
	 * 树高度
	 *
	 * @return
	 */
	public int getHeight() {
		return getHeight(root);
	}

	private int getHeight(TreeNode tree) {
		if (tree == null)
			return 0;// 递归结束:空树高度为0
		else {
			int i = getHeight(tree.getLchild());
			int j = getHeight(tree.getRchild());
			return (i < j) ? (j + 1) : (i + 1);
		}
	}

	/**
	 * 前序遍历 先访问根结点,然后遍历左子树,最后遍历右子树
	 *
	 * @param node
	 */
	public void preOrder(TreeNode node) {
		if (node != null) {
			System.out.println(node.getData());
			preOrder(node.getLchild());
			preOrder(node.getRchild());
		}
	}

	/**
	 * 中序遍历 首先遍历左子树,然后访问根结点,最后遍历右子树
	 *
	 * @param node
	 */
	public void inOrder(TreeNode node) {
		if (node != null) {
			inOrder(node.getLchild());
			System.out.println(node.getData());
			inOrder(node.getRchild());
		}
	}

	/**
	 * 后序遍历 首先遍历左子树,然后遍历右子树,最后遍历访问根结点
	 *
	 * @param node
	 */
	public void postOrder(TreeNode node) {
		if (node != null) {
			postOrder(node.getLchild());
			postOrder(node.getRchild());
			System.out.println(node.getData());
		}
	}

	public static void main(String[] args) {
		TreeNode leaf1 = new TreeNode("5", null, null); // 没有左右孩子节点
		TreeNode leaf2 = new TreeNode("7", null, null); // 没有左右孩子节点
		TreeNode leaf3 = new TreeNode("9", null, null); // 没有左右孩子节点
		TreeNode leaf4 = new TreeNode("11", null, null); // 没有左右孩子节点

		TreeNode n3 = new TreeNode("6", leaf1, leaf2); // 根节点左子树
		TreeNode n4 = new TreeNode("10", leaf3, leaf4); // 根节点右子树
		TreeNode root = new TreeNode("8", n3, n4); // 创建根节点

		BinaryTree bt = new BinaryTree(root);
		System.out.println("=======先序遍历======");
		bt.preOrder(bt.root);
		System.out.println("=======中序遍历======");
		bt.inOrder(bt.root);
		System.out.println("========后续遍历=======");
		bt.postOrder(bt.root);
		System.out.println("===========");
//		System.out.println(bt.getHeight());
//		System.out.println(bt.getSize());
//
//		System.out.println(bt.getParent(leaf1).getData());
	}
}


现在我们来前序遍历二叉树的同事,再颠倒左右孩子。在前序遍历的方法里做一些修改。


//前序遍历并颠倒左右子树
	public void preOrderAndTransform(TreeNode node) {
		if (node != null) {
			// System.out.println(node.getData());
			// 先保存左孩子结点
			TreeNode lNode = node.getLchild();
			node.setLchild(node.getRchild());
			node.setRchild(lNode);
			preOrderAndTransform(node.getLchild());
			preOrderAndTransform(node.getRchild());
		}
	}

测试程序:


public static void main(String[] args) {
		TreeNode leaf1 = new TreeNode("5", null, null); // 没有左右孩子节点
		TreeNode leaf2 = new TreeNode("7", null, null); // 没有左右孩子节点
		TreeNode leaf3 = new TreeNode("9", null, null); // 没有左右孩子节点
		TreeNode leaf4 = new TreeNode("11", null, null); // 没有左右孩子节点

		TreeNode n3 = new TreeNode("6", leaf1, leaf2); // 根节点左子树
		TreeNode n4 = new TreeNode("10", leaf3, leaf4); // 根节点右子树
		TreeNode root = new TreeNode("8", n3, n4); // 创建根节点

		BinaryTree bt = new BinaryTree(root);
		System.out.println("=======先序遍历======");
		bt.preOrder(bt.root);
		System.out.println("=======中序遍历======");
		bt.inOrder(bt.root);
		System.out.println("========后续遍历=======");
		bt.postOrder(bt.root);
		System.out.println("======镜像=====");

		// 镜像颠倒
		bt.preOrderAndTransform(bt.root);
		System.out.println("=======先序遍历======");
		bt.preOrder(bt.root);
		System.out.println("=======中序遍历======");
		bt.inOrder(bt.root);
		System.out.println("========后续遍历=======");
		bt.postOrder(bt.root);
		
		// System.out.println(bt.getHeight());
		// System.out.println(bt.getSize());
		//
		// System.out.println(bt.getParent(leaf1).getData());
	}

输出


=======先序遍历======
8
6
5
7
10
9
11
=======中序遍历======
5
6
7
8
9
10
11
========后续遍历=======
5
7
6
9
11
10
8
颠倒后 : 
=======先序遍历======
8
10
11
9
6
7
5
=======中序遍历======
11
10
9
8
7
6
5
========后续遍历=======
11
9
10
7
5
6
8


循环的话使用while。用游标指向下一个待转换的结点,直到结点的左右孩子都为空。否则颠倒2个字结点。



你可能感兴趣的:(数据结构,算法)