二叉树总结(JAVA)


import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;

public class BinTree {
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		/**
		 * 		     1
		 *          / \
		 *         2   3
		 *        / \  /\
		 *       4  5  6 7
		 *      / \ / \
		 *     8  9 10 11
		 */
		int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
		TreeNode root = createBinTree(a);//完全二叉树
		//levelTravers(root);//层次遍历
		//int levelNum = getLevelNodeNum(root, 4);//K层的节点数
//		List<TreeNode> path = new ArrayList<TreeNode>();
		//getNodePath(root, new TreeNode(5), path);//获取根结点到指定节点之间路径的所有节点
//		getNodePathSenior(root, new TreeNode(11), new TreeNode(6), path);//获取任意2个节点之间路径的所有节点
//		for(TreeNode node : path){
//			System.out.println(node.getData()+" ");
//		}
//		TreeNode lastCommonParent =  findLastCommonParentRec(root, new TreeNode(11), new TreeNode(6));//查找任意2个节点最近的共同祖先
//		System.out.println(lastCommonParent.getData());
//		int maxDistance = getMaxDistance(root);//计算树中2个节点的最远距离
//		System.out.println(maxDistance);
		//干掉4的右孩子
//		root.getLeft().getLeft().setRight(null);
		boolean flag = isCompleteBinaryTree(root);//判断是否为完全二叉树
		System.out.println(flag);
		
		//恢复二叉树
//		int[] pre  =  {1, 2, 4, 8, 9, 5, 10, 11, 3, 6 ,7};
//		int[] min  =  {8, 4, 9, 2, 10, 5, 11, 1, 6, 3, 7};
//		int[] post =  {8, 9, 4, 10, 11, 5, 2, 6, 7, 3, 1};
//		List<TreeNode> preOrder = new ArrayList<TreeNode>();
//		for(int i : pre){
//			preOrder.add(new TreeNode(i));
//		}
//		List<TreeNode> minOrder = new ArrayList<TreeNode>();
//		for(int i : min){
//			minOrder.add(new TreeNode(i));
//		}
//		List<TreeNode> postOrder = new ArrayList<TreeNode>();
//		for(int i : post){
//			postOrder.add(new TreeNode(i));
//		}
//		TreeNode root = rebuildBinaryTreeRec(preOrder, minOrder);//先序+中序
//		TreeNode root = rebuildBinaryTreeRec(minOrder, postOrder, 1);//中序+后序
//		levelTravers(root);
		//判断是否为平衡二叉树
//		TreeNode head = new TreeNode(5);
//		head.setLeft(new TreeNode(4));
//		head.getLeft().setLeft(new TreeNode(1));
//		head.setRight(new TreeNode(6));
//		System.out.print(isAVLTreeRec(head));
		
		
		
	}
	/**
	 * 非递归构建完全二叉树
	 * 这里默认数组是二叉树层次遍历的结果,即由层次遍历的结果恢复二叉树
	 * 这样的数组有一个特点:
	 * 数组下标范围在 [0,treeNodes.length/2 - 1]里的元素全部都是父节点,我们可以根据父节点与子节点的位置关系创建二叉树
	 * 父节点与子节点位置关系:
	 * 左孩子位置:leftChildIndex = parentIndex*2+1;
	 * 右孩子位置: rightChildIndex = parentIndex*2+2
	 * 这里需要注意的一个点是最后一个父节点:
	 * 因为数组个数为奇数的时候,所有的父节点都有左右孩子,而当数组个数为偶数的时候,最后一个父节点没有有孩子。所以我们需要对自后一个父节点左特殊处理,所以我们先构建[0,length/2 - 1)区间的父节点
	 * 因为这些节点肯定是有左右孩子的
	 * @param treeNodes
	 * @return
	 */
	public static TreeNode createBinTree(int[] treeNodes){
		//将数组所有的元素构建成节点存放在List中
		List<TreeNode> nodeList = new ArrayList<TreeNode>();
		for(int i : treeNodes){
			nodeList.add(new TreeNode(i));
		}
		//修改节点之间的关系创建二叉树,先处理一般情况下的父节点
		for(int parentIndex = 0; parentIndex < treeNodes.length/2 - 1; parentIndex++){
			//构建父亲节点的左孩子
			nodeList.get(parentIndex).setLeft(nodeList.get(parentIndex*2+1));
			//构建父亲节点的右孩子
			nodeList.get(parentIndex).setRight(nodeList.get(parentIndex*2+2));
		}
		//特殊处理最后一个父亲节点,因为只有数组个数为奇数的时候,最后一个父亲节点才有右孩子
		int lastParentIndex = treeNodes.length/2-1;
		if(treeNodes.length%2 == 0){
			//偶数,没有右孩子
			nodeList.get(lastParentIndex).setLeft(nodeList.get(lastParentIndex*2+1));
		}else{
			//奇数,有右孩子
			nodeList.get(lastParentIndex).setLeft(nodeList.get(lastParentIndex*2+1));
			nodeList.get(lastParentIndex).setRight(nodeList.get(lastParentIndex*2+2));
		}
		//返回第一个节点,即二叉树的根节点
		return nodeList.get(0);
	}
	/**
	 * 计算二叉树节点的个数
	 * 递归
	 * O(n)
	 */
	public static int getNumRec(TreeNode root){
		if(root == null) return 0;
		return (getNumRec(root.getLeft())+getNumRec(root.getRight())+1);
	}
	/**
	 * 计算二叉树节点的个数
	 * 层次遍历
	 * O(n)
	 */
	public static int getNum(TreeNode root){
		int num = 0;
		if(root == null) return num;
		num = 1;
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		queue.add(root);
		while(!queue.isEmpty()){
			TreeNode node = queue.remove();
			if(node.getLeft() != null){
				queue.add(node.getLeft());
				num++;
			}
			if(node.getRight() != null){
				queue.add(node.getRight());
				num++;
			}
			
		}
		return num;
	}
	
	/**
	 * 求树的深度(高度)
	 * 递归
	 * O(n)
	 */
	public static int getDepthRec(TreeNode root){
		if( root == null) return 0;
		int leftDepth = getDepth(root.getLeft());
		int rightDepth = getDepth(root.getRight());
		return (1+Math.max(leftDepth, rightDepth));
	}
	
	/**
	 * 层次遍历
	 * O(n)
	 */
	public static int getDepth(TreeNode root){
		if(root == null) return 0;
		int depth = 0;
		int currLevelNum = 1;
		int nextLevelNum = 0;
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		queue.add(root);
		while(!queue.isEmpty()){
			TreeNode node = queue.remove();
			currLevelNum--;
			if(node.getLeft()!= null){
				queue.add(node.getLeft());
				nextLevelNum++;
			}
			if(node.getRight() != null){
				queue.add(node.getRight());
				nextLevelNum++;
			}
			if(currLevelNum == 0){
				depth++;
				currLevelNum = nextLevelNum;
				nextLevelNum = 0;
			}
		}
		return depth;
	}
	
	/**
	 * 先序遍历二叉树
	 * 递归
	 */
	public static void preOrderRec(TreeNode node){
		if(node == null) return;
	    System.out.println(node.getData());
	    preOrderRec(node.getLeft());
	    preOrderRec(node.getRight());
	}
	/**
	 * 使用栈进行先序遍历
	 */
	public static void preOrder(TreeNode root){
		if(root == null) return ;
		Stack<TreeNode> stack = new Stack<TreeNode>();
		stack.push(root);
		while(!stack.isEmpty()){
			TreeNode node = stack.pop();
			System.out.println(node.getData());
			//关键点,先入栈右节点
			if(node.getRight() != null) stack.push(node.getRight());
			if(node.getLeft() != null) stack.push(node.getRight());
		}
	}
	
	/**
	 * 中序遍历二叉树
	 * 递归
	 */
	public static void inOrderRec(TreeNode root){
		if(root == null) return;
		inOrderRec(root.getLeft());
		System.out.println(root.getData());
		inOrderRec(root.getRight());
	}
	/**
	 * 后序遍历二叉树
	 * 递归
	 */
	public static void postOrder(TreeNode root){
		if(root == null) return;
		postOrder(root.getLeft());
		postOrder(root.getRight());
		System.out.println(root.getData());
	}
	
	/**
	 * 查找二叉树
	 * 任何一个节点,其左孩子的值<改节点的值,其右孩子的值>该节点的值,是一个特殊的二叉树	
	 * 查找功能
	 * 递归
	 */
	public static TreeNode searchRec(TreeNode root, int key){
		if(root == null) return null;
		int temp = key - root.getData();
		if(temp < 0){
			return searchRec(root.getLeft(), key);
		}else if(temp > 0){
			return searchRec(root.getRight(), key);
		}else{
			return root;
		}
	}
	
	/**
	 * 查找二叉树
	 * 任何一个节点,其左孩子的值<改节点的值,其右孩子的值>该节点的值,是一个特殊的二叉树	
	 * 查找功能
	 * 非递归实现
	 */
	public static TreeNode search(TreeNode root, int key){
		if(root == null) return null;
		while(root != null){
			if(key < root.getData()){
				root = root.getLeft();
			}else if(key < root.getData()){
				root = root.getRight();
			}else{
				return root;
			}
		}
		return root;
	}
	
	/**
	 * 将查找二叉树转换成有序双向链表,不允许创建新节点,只允许修改指针
	 * 递归
	 */
	public static TreeNode convertBTSToDLL(TreeNode root){
		root = convertBTSToDLLSub(root);
		//需要手动处理root引用,将其移动至最左边
		while(root.getLeft() != null){
			root = root.getLeft();
		}
		return root;
	}
	/**
	 * 返回的链表指针指向了链表的中部
	 * @param root
	 * @return
	 */
	public static TreeNode convertBTSToDLLSub(TreeNode root){
			if(root == null || (root.getLeft() == null && root.getRight() == null)) return root;
			//处理左子树
			TreeNode temp = convertBTSToDLLSub(root.getLeft());
			while(temp.getRight() != null){
				temp = temp.getRight();
			}
			//将左子树的最右边和根结点拼接起来
			temp.setRight(root);
			root.setLeft(temp);
			
			//处理右子树,同上
			 TreeNode temp2 = convertBTSToDLLSub(root.getRight());
			 while(temp2.getLeft() != null){
				 temp2 = temp.getLeft();
			 }
			 temp2.setLeft(root);
			 root.setRight(temp2);
			 
			 return root;
			
			
		}
	/**
	 * 层次遍历二叉树
	 * 辅助队列
	 * @param root
	 */
	public static void levelTravers(TreeNode root){
		if(root == null) return;
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		queue.add(root);
		while(!queue.isEmpty()){
			TreeNode node = queue.remove();
			System.out.print(node.getData()+" ");
			if(node.getLeft() != null) queue.add(node.getLeft());
			if(node.getRight() != null) queue.add(node.getRight());
		}
	}
	/**
	 * 计算K层的节点的个数
	 * 层次遍历,输出第K层的节点个数
	 * @param depth
	 * @return
	 */
	public static int getLevelNodeNum(TreeNode root, int depth){
		if(depth == 1) return 1;
		int curLevelN = 1;//二叉树当前层节点从1开始
		int nextLevelN = 0;
		int curDepth = 1;//当前层
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		queue.add(root);
		while(!queue.isEmpty()){
			TreeNode node = queue.remove();
			curLevelN--;
			if(node.getLeft() != null){
				//下一层的节点入队列的时候,进行累加以记录下一层节点的数量
				queue.add(node.getLeft());
				nextLevelN++;
			}
			if(node.getRight() != null){
				queue.add(node.getRight());
				nextLevelN++;
			}
			//当一个节点从对头出队后,判断当前层的是否还有节点,如果没有的话,那就遍历下一层了
			if(curLevelN == 0){
				curLevelN = nextLevelN;//下一层需要遍历的节点个数
				curDepth++;//下一层的深度
				if(curDepth == depth) return curLevelN;
				nextLevelN = 0;
			}
		}
		return 0;//无意义
	}
	/**
	 * 计算二叉树叶子节点的个数
	 * @param root
	 * @return
	 */
	public static int getLeafNodeNum(TreeNode root){
		//思路:层次遍历的过程中,记录既没有左孩子,也没右孩子的节点数,那就是叶子节点数啦。代码编写与层次遍历差不太多
		return 0;
	}
	/**
	 * 判断2个二叉树是否相等
	 * 思路:同时遍历2个二叉树,判断当前节点是否相等,出现不等立即放回false;一直到遍历完为止
	 * 可以先序、中序、后序遍历,可以递归、非递归遍历、层次遍历等
	 * @param firstRoot
	 * @param secondRoot
	 * @return
	 */
	public static boolean isSame(TreeNode firstRoot, TreeNode secondRoot){
		return true;
	}
	/**
	 * 判断是否为平衡二叉树
	 * 平衡二叉树:
	 * 1)左右子树的深度相差不能大于1
	 * 2)左右子树都为平衡二叉树
	 * 3)满足查二叉树的特性
	 * 递归
	 * @param root
	 * @return
	 */
	public static boolean isAVLTreeRec(TreeNode root){
		if(root == null) return true;
		//左右子树的深度差不得超过1
		if(Math.abs(getDepthRec(root.getLeft()) - getDepthRec(root.getRight())) > 1){
			return false;
		}
		//根结点的值大于左孩子
		if(root.getLeft() != null && root.getLeft().getData() >= root.getData()){
			return false;
		}
		//根结点的值必须小于右孩子
		if(root.getRight() != null && root.getRight().getData() <= root.getData()){
			return false;
		}
		//递归判断左右子树也得满足上述特性
		return isAVLTreeRec(root.getLeft()) && isAVLTreeRec(root.getRight());
	}
	
	/**
	 * 求二叉树的镜像
	 * 镜像:
	 * 镜像二叉树的左子树为原二叉树的右子树
	 * 右子树同理
	 * 递归比较简单
	 * @param root
	 * @return
	 */
	public static TreeNode mirrorRec(TreeNode root){
		if(root == null) return null;
		TreeNode mirrorRoot = new TreeNode(root.getData());
		mirrorRoot.setLeft(mirrorRec(root.getRight()));
		mirrorRoot.setRight(mirrorRec(root.getLeft()));
		return mirrorRoot;
	}
	/**
	 * 判断2棵树是否互相为镜像
	 * 递归,其实任何2棵树是否相等除了遍历去比较之外,也可以用此法判定
	 * @param firstRoot
	 * @param secondRoot
	 * @return
	 */
	public static boolean isMirrorRec(TreeNode firstRoot, TreeNode secondRoot){
		if(firstRoot == null && secondRoot == null) return true;
		if(firstRoot == null || secondRoot == null) return false;
		if(firstRoot.getData() != secondRoot.getData()) return false;
		return isMirrorRec(firstRoot.getLeft(), secondRoot.getRight()) && isMirrorRec(firstRoot.getRight(), secondRoot.getLeft());
	}
	/**
	 * 查找二叉树中2个节点最近的共同祖先节点
	 * 递归
	 * 思想:
	 * 1)如果2个节点分别在根结点的2侧,则直接返回根结点,
	 * 2)如果2个节点都在根结点的左侧,那么对根结点的左子树递归处理
	 * 3)如果2个节点都在根结点的右侧,那么对根结点的右子树递归处理
	 * @param root
	 * @param n1
	 * @param n2
	 * @return
	 */
	public static TreeNode findLastCommonParentRec(TreeNode root, TreeNode n1, TreeNode n2){
		if(root == null || n1 == null || n2 == null) return null;
		if(findNodeRec(root.getLeft(), n1)){
			//n1在左子树
			if(findNodeRec(root.getRight(), n2)){
				//n2在右子树
				return root;
			}else{
				//n2在左子树,则在左子树递归处理2个节点
				return findLastCommonParentRec(root.getLeft(), n1, n2);
			}
		}else{
			//n1在右子树
			if(findNodeRec(root.getLeft(), n2)){
				//n2在左子树
				return root;
			}else{
				//n2在右子树,则在右子树中对2个节点递归处理
				return findLastCommonParentRec(root.getRight(), n1, n2);
			}
		}
	}
	/**
	 * 递归查找二叉树中是否存在node节点
	 * 也可以遍历去查找对应的节点,效率也会更高一些
	 * 上一个方法的辅助方法
	 * @param root
	 * @param node
	 * @return
	 */
	public static boolean findNodeRec(TreeNode root, TreeNode node){
		if(root == null || node == null) return false;
		if(root.getData() == node.getData()) return true;
		if(findNodeRec(root.getLeft(), node)){
			//递归左子树OK
			return true;
		}else if(findNodeRec(root.getRight(), node)){
			//递归右子树ok
			return true;
		}
		//没有找到
		return false;
	}
	/**
	 * 递归查找二叉树中是否存在node节点
	 * @param root
	 * @param node
	 * @param arg
	 * @return 查找到的node节点
	 */
	public static TreeNode findNodeRec(TreeNode root, TreeNode node, boolean arg){
		if(root == null || node == null) return null;
		if(root.getData() == node.getData()) return root;
		if(findNodeRec(root.getLeft(), node)){
			//能在左子树找到node节点,继续递归左子树查找节点
			return findNodeRec(root.getLeft(), node, true);
		}else if(findNodeRec(root.getRight(), node)){
			//能在右子树找到节点,继续递归右子树查找节点
			return findNodeRec(root.getRight(), node, true);
		}else{
			//左右子树都找不到节点
			return null;
		}
	}
	/**
	 * 从根结点到指定节点路径之间所有的节点放入集合中
	 * 递归
	 * 思路:将递归函数设计为:将当前节点到指定节点之间路径的所有节点全部放入路径中,能放则放回true,否则放回false
	 * 递归函数实现:
	 * 1)首先从根结点开始,将根结点放入路径中
	 * 2)判定是否已经到了指定节点
	 * 3)若没有到指定节点,递归从左孩子开始放,能放则放回true,否则放回false
	 * 4)若左孩子不能放,那么就放右孩子,递归从右孩子开始放,能放则放回true,否则放回false
	 * 5)左右孩子都不能放,那么表示根结点没有到指定节点的路径,那么从路径中移除根结点,返回false	
	 * @param root
	 * @param node
	 * @param path
	 * @return 
	 */
	public static boolean getNodePath(TreeNode root, TreeNode node, List<TreeNode> path){
		if(root == null || node == null) return false;
		//将当前节点放入path中去
		path.add(root);
		//当前节点就是指定节点,那么肯定能放入路径,放回true
		if(root.getData() == node.getData()) return true;
		//判别从当前节点是到指定节点路径之间的节点是否能全部放入路径中
		//从当前节点的左子树开始试探
		if(getNodePath(root.getLeft(), node, path)){
			//能成功
			return true;
		}else if(getNodePath(root.getRight(), node, path)){//左子树不行,那从右子树开始试探
			//能成功
			return true;
		}else{
			//都不成功,表明当前节点不在路径中,将当前节点从path中移除
			path.remove(root);
			return false;
			
		}
		
	}
	/**
	 * 引申:
	 * 二叉树中任意2个节点,求两个节点路径之间的所有节点 
	 * 思路:将其中一个节点当成根结点,尝试获取路径看是够能成功,如果都不能成功,表明2个节点在一个最近祖先节点的2侧,
	 * 那么找到最近的祖先节点,以祖先节点为根节点,找到2条路径拼接起来就是我们需要的路径啦
	 * @param n1
	 * @param n2
	 * @param path
	 * @return
	 */
	public static boolean getNodePathSenior(TreeNode root, TreeNode n1, TreeNode n2, List<TreeNode> path){
		if(n1 == null || n2 == null) return false;
		//查找树中对应的n1
		n1 = findNodeRec(root, n1, true);
		//查找树中对应的n2
		n2 = findNodeRec(root, n2, true);
		if(getNodePath(n1, n2, path)){
			//以n1节点为根节点能找到路径
			return true;
		}else if(getNodePath(n2, n1, path)){
			//以n2为根结点能找到路径
			return true;
		}else{
			//寻找最近的祖先节点
			TreeNode lastCommonParent = findLastCommonParentRec(root, n1, n2);
			//拼接2个路径
			List<TreeNode> path1 = new ArrayList<TreeNode>();
			List<TreeNode> path2 = new ArrayList<TreeNode>();
			getNodePath(lastCommonParent, n1, path1);
			getNodePath(lastCommonParent, n2, path2);
			path1.remove(0);//最近祖先节点存在于2条路径当中,所以会重复,去重
			//将path1中的节点反序,为了使结果好看,从一个节点到另一个节点的顺序
			List<TreeNode> temp = new ArrayList<>();
			for(int i = path1.size() - 1; i >= 0; i--){
				temp.add(path1.get(i));
			}
			//拼接
			path.addAll(temp);
			path.addAll(path2);
			return true;
		}
	}
	/**
	 * 计算树的2个节点的最大距离
	 * @param root
	 * @return
	 * 思路:
	 * 返回下列3个值中的最大值
	 * 1)计算右子树的深度+1
	 * 2)计算左子树的深度+1
	 * 3)左子树的深度+右子树的深度+1+1(这里需要加2个1)
	 */
	public static int getMaxDistance(TreeNode root){
		if(root == null) return 0;
		int lDepth = getDepth(root.getLeft());
		int rDepth = getDepth(root.getRight());
		return Math.max((lDepth+rDepth+1+1), Math.max(lDepth, rDepth));
	}
	/**
	 * 判断一个树是否为完全二叉树
	 * 完全二叉树:树的深度为n,那么n-1层的节点必须是满的,n层的节点集中在左侧
	 * 思路:非递归比较简单
	 * 层次遍历二叉树,当发现一个节点没有左孩子,那么该节点的右孩子一定要为空,并且后序节点的都没有左右孩子,否则不为完全二叉树
	 * 当发现一个节点没有右孩子,那么后序节点就不能有左右孩子了
	 * @param root
	 * @return
	 */
	public static boolean isCompleteBinaryTree(TreeNode root){
		if(root == null) return false;
		Queue<TreeNode> queue  = new LinkedList<TreeNode>();
		queue.add(root);
		boolean leftNull = false;//当发现没有左孩子的第一个节点是,将其设置为true;然后开始判断该节点是是否有右孩子,后序节点是否有左右孩子
		boolean rightNull = false; //当发现第一个右孩子为空时,触发一个判定,去判定有序节点都不应该有左右孩子
		
		while(!queue.isEmpty()){
			TreeNode node = queue.remove();
			if(leftNull || rightNull){ //后序节点不应该有左右孩子节点
				if(node.getLeft() != null || node.getRight() != null) return false;
			}
			if(node.getLeft() != null) queue.add(node.getLeft());
			if(node.getRight() != null) queue.add(node.getRight());
			if(node.getLeft() == null){
				leftNull = true;//该节点不能有右孩子,后序节点不能有左右孩子
			}
			if(leftNull){ //当发现没有左孩子的第一个节点,开始判断该节点是是否有右孩子
				if(node.getRight() != null) return false;
			}
			//只去用左孩子为空去触发判定是不够的,还需要用右孩子去判定触发
			if(node.getRight() == null){
				rightNull = true;
			}
		}
		return true;
	}
	
	/**
	 * 由先序和中序序列重建二叉树
	 * 思路:
	 * 不断确定根结点,分割出根结点的左子树的先序和中序序列递归重建根结点的左子树,和分割右子树的先序和中序序列递归重建根结点的右子树
	 * 由先序序列的第一个节点确定根结点,然后由根结点在中序序列中找到分割点,分割点左边就是根结点的左子树的中序序列,分割点的右边就是右子树的中序序列
	 * 因为左右子树的长度已经确定,所以可以在先序序列中进行分割,从根结点后面分割出左子树的长度的序列即左子树的先序序列,从根结点后面的左子树长度+1的位置开始分割,得到右子树的先序序列
	 * 然后根据左子树的先序和中序序列递归重建根结点的左子树
	 * 然后根据右子树的先序和中序序列递归重建根结点的右子树
	 * @param preOrder
	 * @param minOrder
	 * @return
	 */
	public static TreeNode rebuildBinaryTreeRec(List<TreeNode> preOrder, List<TreeNode> minOrder){
		TreeNode root = null;
		List<TreeNode> leftPreOrder;
		List<TreeNode> rightPreOrder;
		List<TreeNode> leftMinOrder;
		List<TreeNode> rightMinOrder;
		int prePos;//先序序列分割点
		int minPos;//中序序列分割点
		if(preOrder.size() > 0 && minOrder.size() > 0){
			//构建根结点
			root = new TreeNode(preOrder.get(0));//先序序列的第一个节点为根结点
			//划分中序序列的左右子树,即左子树和右子树的中序序列
			minPos = minOrder.indexOf(preOrder.get(0));
			leftMinOrder = minOrder.subList(0, minPos);
			rightMinOrder = minOrder.subList(minPos+1,minOrder.size());
			//划分先序序列的左右子树,即左子树和右子树的先序序列
			prePos = leftMinOrder.size();//左子树的长度
			leftPreOrder = preOrder.subList(1, prePos+1);
			rightPreOrder = preOrder.subList(prePos+1, preOrder.size());
			//递归构建左子树,右子树
			root.setLeft(rebuildBinaryTreeRec(leftPreOrder, leftMinOrder));
			root.setRight(rebuildBinaryTreeRec(rightPreOrder, rightMinOrder));
		}
		return root;
	}
	/**
	 * 中序+后序恢复二叉树
	 * 思路和上边差不多
	 * @param minOrder
	 * @param postOrder
	 * @param op
	 * @return
	 */
	public static TreeNode rebuildBinaryTreeRec(List<TreeNode> minOrder, List<TreeNode> postOrder, int op){
		TreeNode root = null;
		List<TreeNode> leftMinOrder = null;
		List<TreeNode> leftPostOrder = null;
		List<TreeNode> rightMinOrder = null;
		List<TreeNode> rightPostOrder = null;
		int minPos = 0;
		int postPos = 0;
		if(minOrder.size() > 0 && postOrder.size() > 0){
			//后序遍历的最后一个节点是根结点
			root = new TreeNode(postOrder.get(postOrder.size()-1));
			//分割左右子树的中序序列
			minPos = minOrder.indexOf(root);
			leftMinOrder = minOrder.subList(0, minPos);
			rightMinOrder = minOrder.subList(minPos+1, minOrder.size());
			//分割左右子树的后序序列
			postPos = leftMinOrder.size();
			leftPostOrder = postOrder.subList(0, postPos);
			rightPostOrder = postOrder.subList(postPos, postOrder.size()-1);
			//递归重建左子树,右子树
			root.setLeft(rebuildBinaryTreeRec(leftMinOrder, leftPostOrder, 1));
			root.setRight(rebuildBinaryTreeRec(rightMinOrder, rightPostOrder, 1));
		}
		return root;
	}
}

/**
 * 树的节点
 */
class TreeNode{
	private TreeNode left;
	private TreeNode right;
    private int data;
    private String id = "id";
    TreeNode(){};
	TreeNode(int data){
		this.data = data;
	};
	TreeNode(TreeNode node){
		this.left = node.left;
		this.right = node.right;
		this.data = node.data;
	}
	public void setLeft(TreeNode left){
		this.left = left;
	}
	public TreeNode getLeft(){
		return this.left;
	}
	public void setRight(TreeNode right){
		this.right = right;
	}
	public TreeNode getRight(){
		return this.right;
	}
	public void setData(int data){
		this.data = data;
	}
	public int getData(){
		return this.data;
	}
	public boolean equals(Object obj){
		if(obj instanceof TreeNode){
			TreeNode node = (TreeNode) obj;
			return (this.data == node.data);
		}
		return super.equals(obj);
	}
	/**
	 * 需要重新复写hashCode方法,因为在散列集合中,是根据equals和hashCode()共同来决定2者是否相等;
	 * 规则:2者相等,equals返回true,hashCode相等;2者不相等,equals返回false, 但是hashCode不一定不相等,因为不同对象可能散列出相等的hashCode;
	 * 这里使用的是id 的hashCode; 表示data相等,因为hashCode一定行等,那么2者就相等
	 */
	public int hashCode(){
		return this.id.hashCode();
	}
	
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值