平衡二叉树java实现

一、认识平衡二叉搜索树

AVL平衡二叉搜索树:
特性
1、拥有BST(二叉搜索树)基本特性
2、左右子树深度之差的绝对值不超过1(左子树节点数减右子树节点数值要等于0、1、-1)
优点
1、拥有BST(二叉搜索树)的优点,并不会使其失衡,从而提高查找运算的速度
缺点
1、为了保持绝对平衡,会进行检查判断,如果失衡则需要旋转去改变树结构,使其保持平衡(频繁插入、删除很影响性能),插入新节点后需要旋转的次数不可预知

认识旋转规则:

平衡二叉树旋转详解

	在学习平衡二叉树时,我们需要对平衡二叉树有一些了解,比如:
	
	平衡二叉树旋转分为4种情况 LL型、RR型、LR型、RL型
		LL型:
			新插入节点在X节点的左子树的左子树中
		RR型:
			新插入节点在X节点的右子树的右子树中
		LR型:
			新插入节点在X节点的左子树的右子树中
		RL型:
			新插入节点在X节点的右子树的左子树中
	
	x节点: 我们进行左旋右旋操作的时候,x节点就是我们旋转的轴
	
	平衡因子: 左子树最大深度 - 右子树最大深度 的绝对值,平衡因子为0、1则为平衡,否则为不平衡
	
	最小不平衡树: 在新插入的结点向上查找,以第一个平衡因子的绝对值超过1的结点为根的子树称为最小不平衡子树

	
	性质:
		1、平衡因子不大于0
		2、左右子树都为平衡树

LL型图示例:
在这里插入图片描述

Java实现

1、定义节点类,使节点与二叉树分离

public class Node {

	int value;
	
	Node leftChild;
	
	Node rightChild;
	
	
	Node(int value) {
		this.value = value;
	}
	
	public void display() {
		System.out.println(this.value + "\t");
	}

	@Override
	public String toString() {
		return String.valueOf(value);
	}

	public int value() {
		return value;
	}

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

	public Node leftChild() {
		return leftChild;
	}

	public void leftChild(Node leftChild) {
		this.leftChild = leftChild;
	}

	public Node rightChild() {
		return rightChild;
	}

	public void rightChild(Node rightChild) {
		this.rightChild = rightChild;
	}
	
	
}
}

2、逻辑实现类



public class BinaryTree {

	private Node root = null;
	
	BinaryTree(int value){
		root = new Node(value);
		root.rightChild(null);
		root.leftChild(null);
	}
	
	/**
	 * 查找
	 * @param value
	 * @return
	 */
	public Node findKey(int value) {
		Node tree = root;

		int treeValue = tree.value();
		while (true) {
			if (value == treeValue) {
				return tree;
			} else if (value < treeValue) {
				tree = tree.leftChild();
			} else if (value > treeValue) {
				tree = tree.rightChild();
			}
			if (tree == null) {
				return null;
			}
		}
	}
	
    /**
     * 插入
     * @param value
     * @return
     */
    public boolean insert(int value) {
    	
    	boolean success = true;
    	if (null == root) {
    		new BinaryTree(value);
		} else {
			Node current = root;
			Node parent = null;
			while (true) {
				if (current.value() > value) {
					parent = current;
					current = current.leftChild;
					if (null == current) {
						parent.leftChild(new Node(value));
						break;
					}
				} else if (current.value() < value) {
					parent = current;
					current = current.rightChild;
					if (null == current) {
						parent.rightChild(new Node(value));
						break;
					}
				} else {
					success = false;
				}
			}
		}
    	return success;
    	
    }
    
    /**
	 * 	  //中序遍历(递归):
	 *    1、调用自身来遍历节点的左子树
	 *    2、访问这个节点
	 *    3、调用自身来遍历节点的右子树
     */
    public void inOrderTraverse() {
    	System.out.println("中序遍历:");
    	inOrderTraverse(root);
    }
    
	private void inOrderTraverse(Node node) {
		if (node == null) 
			return ;
		
		inOrderTraverse(node.leftChild);
		node.display();
		inOrderTraverse(node.rightChild);
	}
    public void inOrderByStack() {
    	
    	System.out.println("中序非递归遍历");
    	Stack<Node> stack = new Stack<>();
    	Node current = root;
    	while (current != null || stack.isEmpty()) {
    		while (current != null) {
    			stack.push(current);
				current = current.leftChild;
			}
    		if (!stack.isEmpty()) {
    			current = stack.pop();
    			current.display();
    			current = current.rightChild;
			}
		}
    	
    } 
    public void preOrderTraverse() {
    	System.out.println("前序递归遍历");
    	preOrderTraverse(root);
    }  
    private void preOrderTraverse(Node node) {
    	
    	if (null == node) {
			return;
		}
    	
    	node.display();
		preOrderTraverse(node.leftChild);
		preOrderTraverse(node.rightChild);
	}

	public void preOrderByStack() {
		
		System.out.println("前序遍历非递归操作");
		Stack<Node> stack = new Stack<>();
		Node current = root;
		while (null != current || !stack.isEmpty()) {
			while (null != current) {
				stack.push(current.leftChild);
				current = current.leftChild;
			}
			if (!stack.isEmpty()) {
				current = stack.pop();
				current = current.rightChild;
			}
		}
		
	}  
    public void postOrderTraverse() {
    	System.out.println("后序遍历");
    	postOrderTraverse(root);
    } 
    private void postOrderTraverse(Node node) {
		if (null == node) {
			return;
		}
		
		postOrderTraverse(node.leftChild);
		postOrderTraverse(node.rightChild);
		node.display();
	}
    
	public void postOrderByStack() {
		
		System.out.println("后序遍历非递归操作");
		Stack<Node> stack = new Stack<>();
		Node current = root;
		Node preNode = null;
		
		while (null != current || !stack.isEmpty()) {
			while (null != current) {
				stack.push(current);
				current.display();
				current = current.leftChild;
			}
			
			if (!stack.isEmpty()) {
				current = stack.peek().rightChild;
				if (current == null || current == preNode) {
					current = stack.pop();
					current.display();
					preNode = current;
					current = null; 
				}
			}
		}
		
	}  
	
	
    /**
     * 得到最小(大)值
     * @return
     */
    public int getMinValue() {
    	Node current = root;
    	while (true) {
			if (null == current.leftChild) {
				return current.value();
			}
			current = current.leftChild;
		}
    	
    }
    
    public int getMaxValue() {
    	Node current = root;
    	while (true) {
			if (null == current.rightChild) {
				return current.value();
			}
			current = current.rightChild;
		}
    }
    
    public boolean delete(int value) {
		Node current = root;    //需要删除的节点
		Node parent = null;     //需要删除的节点的父节点
		boolean isLeftChild = true;   //需要删除的节点是否父节点的左子树
		
		while (true) {
			if (value == current.value) {
				break;
			} else if (value < current.value) {
				isLeftChild = true;
				parent = current;
				current = current.leftChild;
			} else {
				isLeftChild = false;
				parent = current;
				current = current.rightChild;
			}
			
			//找不到需要删除的节点,直接返回
			if (current == null)
				return false;
		}
		
		//分情况考虑
		//1、需要删除的节点为叶子节点
		if (current.leftChild == null && current.rightChild == null) {
			//如果该叶节点为根节点,将根节点置为null
			if (current == root) {
				root = null;
			} else {
				//如果该叶节点是父节点的左子节点,将父节点的左子节点置为null
				if (isLeftChild) {
					parent.leftChild  = null;
				} else { //如果该叶节点是父节点的右子节点,将父节点的右子节点置为null
					parent.rightChild = null;
				}
			}
		} 
		//2、需要删除的节点有一个子节点,且该子节点为左子节点
		else if (current.rightChild == null) {
			//如果该节点为根节点,将根节点的左子节点变为根节点
			if (current == root) {
				root = current.leftChild;
			} else {
				//如果该节点是父节点的左子节点,将该节点的左子节点变为父节点的左子节点
				if (isLeftChild) {
					parent.leftChild = current.leftChild;
				} else {  //如果该节点是父节点的右子节点,将该节点的左子节点变为父节点的右子节点
					parent.rightChild = current.leftChild;
				}
			}
		}
		//2、需要删除的节点有一个子节点,且该子节点为右子节点
		else if (current.leftChild == null) {
			//如果该节点为根节点,将根节点的右子节点变为根节点
			if (current == root) {
				root = current.rightChild;
			} else {
				//如果该节点是父节点的左子节点,将该节点的右子节点变为父节点的左子节点
				if (isLeftChild) {
					parent.leftChild = current.rightChild;
				} else {  //如果该节点是父节点的右子节点,将该节点的右子节点变为父节点的右子节点
					parent.rightChild = current.rightChild;
				}
			}
		}
		//3、需要删除的节点有两个子节点,需要寻找该节点的后续节点替代删除节点
		else {
			Node successor = getSuccessor(current);
			//如果该节点为根节点,将后继节点变为根节点,并将根节点的左子节点变为后继节点的左子节点
			if (current == root) {
				root = successor;
			} else {
				//如果该节点是父节点的左子节点,将该节点的后继节点变为父节点的左子节点
				if (isLeftChild) {
					parent.leftChild = successor;
				} else {  //如果该节点是父节点的右子节点,将该节点的后继节点变为父节点的右子节点
					parent.rightChild = successor;
				}
			}
		}
		current = null;
		return true;

    } //删除
    
    
    /**
	 * 
	 * 得到后继节点,即删除节点的左后代
	 */
	private Node getSuccessor(Node delNode) {
		Node successor = delNode;
		Node successorParent = null;
		Node current = delNode.rightChild;
		
		while (current != null) {
			successorParent = successor;
			successor = current;
			current = current.leftChild;
		}
		
		//如果后继节点不是删除节点的右子节点时,
		if (successor != delNode.rightChild) {
			//要将后继节点的右子节点指向后继结点父节点的左子节点,
			successorParent.leftChild = successor.rightChild;
			//并将删除节点的右子节点指向后继结点的右子节点
			successor.rightChild = delNode.rightChild;
		}
		//任何情况下,都需要将删除节点的左子节点指向后继节点的左子节点
		successor.leftChild = delNode.leftChild;
		
		return successor;
	}

3、测试验证


	
    public static void main(String[] args) {
		BinaryTree bt = new BinaryTree(52);
		bt.insert(580);
		bt.insert(12);
		bt.insert(50);
		bt.insert(58);
		bt.insert(9);
		bt.insert(888);
		bt.insert(248);
		bt.insert(32);
		bt.insert(666);
		bt.insert(455);
		bt.insert(777);
		bt.insert(999);
		bt.inOrderTraverse();
		bt.preOrderTraverse();
		bt.postOrderTraverse();
		System.out.println(bt.findKey(32));
		System.out.println(bt.findKey(81));
		System.out.println("最小值:" + bt.getMinValue());
		bt.delete(52);       //删除有两个子节点的节点,且删除节点为根节点
	
		bt.inOrderTraverse();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值