二叉树的遍历、查找、插入、删除等

1,359 阅读3分钟
/********************************************
 * All Rights Reserved By www.laughing.ren
 * @author:Laughing_Lz
 * @version:2018年11月29日 下午11:33:24
 * ******************************************/
package ren.laughing.code.Test;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 二叉树
 * 
 * @author Laughing_Lz
 *
 */
public class Tree {

	/**
	 * 前序遍历二叉树
	 * 
	 * @param root
	 */
	public static void preOrder(Node root) {
		if (root == null) {
			return;
		}
		System.out.print(root.getValue() + " ");
		if (root.getLeft() != null) {
			preOrder(root.getLeft());
		}
		if (root.getRight() != null) {
			preOrder(root.getRight());
		}
	}

	/**
	 * 中序遍历二叉树
	 * 
	 * @param root
	 */
	public static void inOrder(Node root) {
		if (root == null) {
			return;
		}
		if (root.getLeft() != null) {
			inOrder(root.getLeft());
		}
		System.out.print(root.getValue() + " ");
		if (root.getRight() != null) {
			inOrder(root.getRight());
		}
	}

	/**
	 * 后序遍历二叉树
	 * 
	 * @param root
	 */
	public static void postOrder(Node root) {
		if (root == null) {
			return;
		}
		if (root.getLeft() != null) {
			postOrder(root.getLeft());
		}
		if (root.getRight() != null) {
			postOrder(root.getRight());
		}
		System.out.print(root.getValue() + " ");
	}

	/**
	 * 层次遍历二叉树
	 * 
	 * @param root
	 */
	public static void levelOrder(Node root) {
		if (root == null) {
			return;
		}
		Queue<Node> queue = new LinkedList<Node>();
		queue.add(root);
		while (!queue.isEmpty()) {
			Node currentNode = queue.poll();
			System.out.print(currentNode.getValue() + " ");
			if (currentNode.getLeft() != null) {
				queue.add(currentNode.getLeft());
			}
			if (currentNode.getRight() != null) {
				queue.add(currentNode.getRight());
			}
		}
	}

	/**
	 * 卡特兰数: 给定一组数据,比如 1,3,5,6,9,10。你来算算,可以构建出多少种不同的二叉树?
	 * https://en.wikipedia.org/wiki/Catalan_number
	 * 
	 * @param numKeys
	 * @return
	 */
	public static int countTrees(int numKeys) {
		if (numKeys <= 1) {
			return (1);
		} else {
			int sum = 0;
			int left, right, root;
			// 每次迭代,root节点的左右两颗子树的节点数不同--左子树的节点数从0到numKeys-1,右子树相反
			// 这样迭代结束后,各种情况便都覆盖全了;
			for (root = 1; root <= numKeys; root++) {
				left = countTrees(root - 1);
				right = countTrees(numKeys - root);

				// number of possible trees with this root == left*right
				sum += left * right;
			}
			return (sum);
		}
	}

	static class Node {
		private int value;
		private Node left;
		private Node right;

		public Node(int value) {
			super();
			this.value = value;
		}

		public Node() {
			super();
		}

		public Node getLeft() {
			return left;
		}

		public void setLeft(Node left) {
			this.left = left;
		}

		public Node getRight() {
			return right;
		}

		public void setRight(Node right) {
			this.right = right;
		}

		public void setValue(int value) {
			this.value = value;
		}

		public int getValue() {
			return this.value;
		}
	}

	/**
	 * 二叉查找树的查找操作 二叉查找树:每个节点的左节点都比当前节点值小,右节点都比当前节点大值。
	 * 
	 * @param root
	 * @param value
	 * @return
	 */
	public static Node find(Node root, int value) {
		if (root == null) {
			return null;
		}
		while (root != null) {
			if (root.getValue() == value) {
				return root;
			} else if (root.getValue() > value) {
				root = root.getLeft();
			} else if (root.getValue() < value) {
				root = root.getRight();
			}
		}
		return null;
	}

	/**
	 * 二叉查找树的插入操作
	 * 
	 * @param root
	 * @param value
	 */
	public static void insert(Node root, int value) {
		if (root == null) {
			root = new Node(value);
		}
		while (root != null) {
			if (root.getValue() < value) {
				if (root.getRight() == null) {
					root.setRight(new Node(value));
					return;
				}
				root = root.getRight();
			} else if (root.getValue() > value) {
				if (root.getLeft() == null) {
					root.setLeft(new Node(value));
					return;
				}
				root = root.getLeft();
			}
		}
	}

	/**
	 * 二叉查找树的删除操作,要注意有三种情况:1、待删除节点没有子节点2、待删除节点只有一个子节点(只需更新父节点)
	 * 3、待删除节点有两个子节点(从待删除节点的左子节点中找出最大的节点替换,或从右子节点中找出最小的节点替换)
	 * 
	 * @param tree
	 * @param data
	 */
	public static void delete(Node tree, int data) {
		Node p = tree; // p 指向要删除的节点,初始化指向根节点
		Node pp = null; // pp 记录的是 p 的父节点
		while (p != null && p.getValue() != data) {
			pp = p;
			if (data > p.getValue())
				p = p.right;
			else
				p = p.left;
		}
		if (p == null)
			return; // 没有找到

		// 要删除的节点有两个子节点
		if (p.left != null && p.right != null) { // 查找右子树中最小节点
			Node minP = p.right;
			Node minPP = p; // minPP 表示 minP 的父节点
			while (minP.left != null) {
				minPP = minP;
				minP = minP.left;
			}
			p.setValue(minP.getValue()); // 将 minP 的数据替换到 p 中
			p = minP; // 下面就变成了删除 minP 了
			pp = minPP;
		}

		// 删除节点是叶子节点或者仅有一个子节点
		Node child; // p 的子节点
		if (p.left != null)
			child = p.left;
		else if (p.right != null)
			child = p.right;
		else
			child = null;

		if (pp == null)
			tree = child; // 删除的是根节点
		else if (pp.left == p)
			pp.left = child;
		else
			pp.right = child;

		System.out.println("\n删除节点" + data + "后:");
		inOrder(tree);
	}

	/**
	 * 计算二叉树的高度
	 *
	 * @param root
	 * @param index
	 * @return
	 */
	public static int getBinaryLevel(Node root, int index) {
		if (null == root) {
			return index;
		}

		int maxleftLevel = 0;
		if (root.left != null) {
			maxleftLevel = getBinaryLevel(root.left, index + 1);
		}

		int maxRightLevel = 0;

		if (root.right != null) {
			maxRightLevel = getBinaryLevel(root.right, index + 1);
		}

		return Math.max(maxleftLevel, maxRightLevel) + 1;
	}

	public static void main(String[] args) {
		// 构建二叉树
		Node leaf1 = new Node(6);
		Node leaf2 = new Node(9);
		Node leaf3 = new Node(10);
		Node node1 = new Node(3);
		node1.setLeft(leaf1);
		node1.setRight(leaf2);
		Node node2 = new Node(5);
		node2.setLeft(leaf3);
		Node root = new Node(1);
		root.setLeft(node1);
		root.setRight(node2);
		// 构建中序遍历有序的二叉查找树
		Node leaf11 = new Node(1);
		Node leaf22 = new Node(5);
		Node leaf33 = new Node(9);
		Node node11 = new Node(3);
		node11.setLeft(leaf11);
		node11.setRight(leaf22);
		Node node22 = new Node(10);
		node22.setLeft(leaf33);
		Node root1 = new Node(6);
		root1.setLeft(node11);
		root1.setRight(node22);

		System.out.println("前序遍历:");
		preOrder(root);
		System.out.println("\n中序遍历:");
		inOrder(root);
		System.out.println("\n后序遍历:");
		postOrder(root);
		System.out.println("\n层次遍历:");
		levelOrder(root);
		System.out.print("\n计算卡特兰数:\n" + countTrees(3));
		System.out.print("\n二叉查找树的查找操作:\n" + find(root1, 6).value);
		System.out.print("\n计算二叉树高度:\n" + getBinaryLevel(root, 0));
		System.out.println("\n二叉查找树的插入操作:");
		insert(root1, 11);
		System.out.println("\n二叉查找树插入节点11后:");
		inOrder(root1);
		System.out.println("\n二叉查找树的删除操作:");
		delete(root1, 6);
	}
}