【面试】【二叉树】java 实现二叉树插入、旋转调整维护自平衡

1.定义节点对象

package com.wang.tree;
/**
 * 二叉树节点类
 * @description
 * @author wang
 * @date 2018年11月20日
 */
public class TreeNode {
	private int data;
	private TreeNode leftNode;
	private TreeNode rightNode;
	private TreeNode parentNode;
	
	public TreeNode() {
		super();
		// TODO 自动生成的构造函数存根
	}
	
	public TreeNode(int data) {
		super();
		this.data = data;
	}

	public int getData() {
		return data;
	}

	public void setData(int data) {
		this.data = data;
	}

	public TreeNode getLeftNode() {
		return leftNode;
	}
	public void setLeftNode(TreeNode leftNode) {
		this.leftNode = leftNode;
	}
	public TreeNode getRightNode() {
		return rightNode;
	}
	public void setRightNode(TreeNode rightNode) {
		this.rightNode = rightNode;
	}
	public TreeNode getParentNode() {
		return parentNode;
	}
	public void setParentNode(TreeNode parentNode) {
		this.parentNode = parentNode;
	}
	
	
	

}

2.工具类加入 插入、左旋、右旋等方法

package com.wang.tree;
/**
 * 二叉平衡树(AVL树)
 * @description
 * @author wang
 * @date 2018年11月20日
 */
public class AVLTreeUtil {
	/**
	 * 判断二叉树是否是平衡二叉树
	 * 缺点:重复的计算子树的高度
	 * @param node (root根节点,迭代遍历)
	 * @return
	 */
	public static boolean isBalance=true;
	public static boolean isBalanced(TreeNode node){
		//如果是空树,则是平衡二叉树
		if(null == node){
			return true;
		}
		//如果不为空
		//左子树或者右子树为空,则高度差肯定小于2则为平衡二叉树
		if(null == node.getLeftNode() || null == node.getRightNode()){
			return true;
		}
		//如果左子树或者右子树都不为空,则比较高度差
		// 计算得到左子树的深度
        int leftDepth = treeDepth(node.getLeftNode());
        // 计算得到右子树的深度
        int rightDepth = treeDepth(node.getRightNode());
        // 如果高度差大于1,不满足平衡二叉的条件
        if (Math.abs(leftDepth - rightDepth) > 1) {
            return false;
        }
        // 判断左子树和右子树是否满足平衡二叉树的条件
        return isBalanced(node.getLeftNode()) && isBalanced(node.getRightNode());
	}
	
	public static int treeDepth(TreeNode node){
		if(null == node){
			return 0;
		}
		//计算左子树的深度
		int left = treeDepth(node.getLeftNode());
		//计算右子树的深度
		int right = treeDepth(node.getRightNode());
		// 树root的深度=路径最长的子树深度 + 1
		return left >= right ? (left + 1) : (right + 1);
	}
	/**
	 * 可以用后序遍历,从下到上遍历如果子树中任一不满足条件返回 false<p>
     * 否则返回 true 这样每个节点的高度只会算一次
	 * @param node
	 * @return
	 */
	public static boolean isBalanced1(TreeNode node){
		treeDepth1(node);
		return isBalance;
	}
	public static int treeDepth1(TreeNode root){
		if(root==null)
            return 0;
        int left=treeDepth1(root.getLeftNode());
        //左子树高度
        int right=treeDepth1(root.getRightNode());
        //右子树高度
        if(Math.abs(left-right)>1)
        {
            isBalance=false;
            //只要有一个子树的左右子树的高度绝对值大于 1 isBalance=false
        }
        return Math.max(left, right)+1;
	}
	
	/**
	 * 向AVL树中插入数据
	 * @param root
	 * @param Data
	 */
	public static void add(TreeNode root, int data){
		if(data < root.getData()){
			if(root.getLeftNode() != null){
				add(root.getLeftNode(),data);
			}else{
				TreeNode newLeftNode = new TreeNode(data);
				root.setLeftNode(newLeftNode);
				newLeftNode.setParentNode(root);
			}
		}else{
			if(root.getRightNode() != null){
				add(root.getRightNode(),data);
			}else{
				TreeNode newRightNode = new TreeNode(data);
				root.setRightNode(newRightNode);
				newRightNode.setParentNode(root);
			}
		}
		//插入完成
		//如果不再平衡,需要旋转
		int balance = calculateBalance(root);
		//左子树高,应该右旋(包括左左,左右)
		if(balance >= 2){
			//右孙高,先左旋(左右,旋转两次,先左旋再右旋)
			if(calculateBalance(root.getLeftNode()) == -1){
				left_rotate(root.getLeftNode());
			}
			//(左左,旋转一次,直接右旋)
			right_rotate(root);
		}
		
		//右子树高,应该左旋(包括右右,右左)
		if(balance <= -2){
			//左孙高,先右旋(右左,旋转两次,先右旋再左旋)
			if(calculateBalance(root.getRightNode()) == 1){
				right_rotate(root.getRightNode());
			}
			//(右右,旋转一次,直接左旋)
			left_rotate(root);
		}
		
	}
	
	/**
	 * 插入新节点
	 * @param root
	 * @param data
	 */
	public static void insert(TreeNode root, int data){
		if(data < root.getData()){
			if(root.getLeftNode() != null){
				insert(root.getLeftNode(),data);
			}else{
				TreeNode newLeftNode = new TreeNode(data);
				root.setLeftNode(newLeftNode);
				newLeftNode.setParentNode(root);
			}
		}else{
			if(root.getRightNode() != null){
				insert(root.getRightNode(),data);
			}else{
				TreeNode newRightNode = new TreeNode(data);
				root.setRightNode(newRightNode);
				newRightNode.setParentNode(root);
			}
		}
	}
	
	/**
	 * 计算平衡因子(左右子树高度(深度)之差)
	 * @param root
	 * @return
	 */
	public static int calculateBalance(TreeNode root){
		if(root == null){
			return 0;
		}
		//计算左子树的深度
		int left = treeDepth(root.getLeftNode());
		//计算右子树的深度
		int right = treeDepth(root.getRightNode());
		return (left-right);
		
	}
	
	/**
	 * 左旋
	 * @param root
	 */
	public static void left_rotate(TreeNode p){
		//父节点
		TreeNode pParent = p.getParentNode();
		//右子节点
		TreeNode pRight = p.getRightNode();
		//右子节点的左节点(孙节点)
		TreeNode pRightLeft = pRight.getLeftNode();
		//右子节点变父
		pRight.setParentNode(pParent);
		if(pParent != null){
			if(p == pParent.getLeftNode()){
				pParent.setLeftNode(pRight);
			}else if(p == pParent.getRightNode()){
				pParent.setRightNode(pRight);
			}
		}
		pRight.setLeftNode(p);
		p.setParentNode(pRight);
		//右左孙变右子
		p.setRightNode(pRightLeft);
		if(pRightLeft != null){
			pRightLeft.setParentNode(p);
		}
	}
	
	
	/**
	 * 右旋
	 * @param root
	 */
    public static void right_rotate(TreeNode p){
    	//父节点
    	TreeNode pParent = p.getParentNode();
    	//左子节点
    	TreeNode pLeft = p.getLeftNode();
    	//左子节点的右节点(孙节点)
    	TreeNode pLeftRight = pLeft.getRightNode();
    	//左子变父
    	pLeft.setParentNode(pParent);
    	//判断p原来是pParent的左子还是右子,并改为赋予pLeft
    	if(pParent != null){
    		if(p == pParent.getLeftNode()){
    			pParent.setLeftNode(pLeft);
    		}else if(p == pParent.getRightNode()){
    			pParent.setRightNode(pLeft);
    		}
    	}
    	pLeft.setRightNode(p);
    	p.setParentNode(pLeft);
    	//左右孙变左子
    	p.setLeftNode(pLeftRight);
    	if(pLeftRight != null){
    		pLeftRight.setParentNode(p);
    	}
		
	}
    
    /**
     * 前序遍历 中--左--右(DLR)
     * @param root
     */
    public static void preorderTraversal(TreeNode root){
    	if(root != null){
    		System.out.println(root.getData() +"->");
    		preorderTraversal(root.getLeftNode());
    		preorderTraversal(root.getRightNode());
    		
    	}
    }
    
    /**
     * 中序遍历 左--中--右(LDR)
     * @param root
     */
    public static void inorderTraversal(TreeNode root){
    	if(root != null){
    		inorderTraversal(root.getLeftNode());
    		System.out.println(root.getData() +"->");
    		inorderTraversal(root.getRightNode());
    		
    	}
    }
    
    /**
     * 后序遍历 左--右--中(LRD)
     * @param root
     */
    public static void postorderTraversal(TreeNode root){
    	if(root != null){
    		postorderTraversal(root.getLeftNode());
    		postorderTraversal(root.getRightNode());
    		System.out.println(root.getData() +"->");
    	}
    }
    
	
	

}

3.测试代码

package com.wang.tree;
/**
 * 测试二叉平衡树插入
 * @description
 * @author wang
 * @date 2018年11月22日
 */
public class AVLTreeTest2 {
	public static void main(String[] args) {
		TreeNode root = new TreeNode(5);
		TreeNode node2 = new TreeNode(3);
		TreeNode node3 = new TreeNode(6);
		TreeNode node4 = new TreeNode(1);
		TreeNode node5 = new TreeNode(4);
		root.setLeftNode(node2);
		root.setRightNode(node3);
		node2.setParentNode(root);
		node2.setLeftNode(node4);
		node2.setRightNode(node5);
		node4.setParentNode(node2);
		node5.setParentNode(node2);
		System.out.println("=====开始中序遍历=====");
		AVLTreeUtil.inorderTraversal(root);
		AVLTreeUtil.add(root, 2);
		System.out.println("=====开始中序遍历=====");
		AVLTreeUtil.inorderTraversal(node2);
	}
	

}

输出结果:

=====开始中序遍历=====
1->
3->
4->
5->
6->
=====开始中序遍历=====
1->
2->
3->
4->
5->
6->

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值