JAVA代码实现平衡二叉树

平衡二叉树

平衡二叉树又叫AVL树,它是在二叉排序树的基础上进行了树结构的调整,使其根节点的左右子树的高度差一致。可以保证查询效率更加高效。
平衡二叉树涉及到左旋转、右旋转和双旋转,接下来分别用图解分析一下:

左旋转

在这里插入图片描述

右旋转

在这里插入图片描述

双旋转

在这里插入图片描述
代码如下:

package com.avl;

/*
 * 平衡二叉树:
 * 1.左旋转
 * 2.右旋转
 * 3.双旋转
 */
public class AVLTreeDemo2 {

	public static void main(String[] args) {
		int[] arr = { 4, 3, 6, 5, 7, 8 };// 左旋转
		// int[] arr = { 10, 12, 8, 9, 7, 6 };// 右旋转
		// int[] arr = { 10, 11, 7, 6, 8, 9 };// 双旋转
		AVLTree2 avlTree2 = new AVLTree2();
		for (int i = 0; i < arr.length; i++) {
			avlTree2.add(new Node2(arr[i]));
		}

		System.out.println("树的高度=" + avlTree2.getRoot().height());
		System.out.println("左子树的高度=" + avlTree2.getRoot().leftHeight());
		System.out.println("右子树的高度=" + avlTree2.getRoot().rightHeight());
		System.out.println("前序遍历");
		avlTree2.preList();
		System.out.println("中序遍历");
		avlTree2.infixList();
	}

}

//创建平衡二叉树
class AVLTree2 {
	Node2 root;

	public Node2 getRoot() {
		return root;
	}

	// 前序遍历
	public void preList() {
		if (root == null) {
			System.out.println("空树无法遍历!");
			return;
		}
		root.preList();
	}

	// 中序遍历
	public void infixList() {
		if (root == null) {
			System.out.println("空树无法遍历!");
			return;
		}
		root.infixList();
	}

	/**
	 * 添加节点
	 * 
	 * @param node
	 */
	public void add(Node2 node) {
		if (root == null) {
			root = node;
			return;
		}
		root.add(node);
	}
}

//创建节点类
class Node2 {
	int value;
	Node2 left;
	Node2 right;

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

	@Override
	public String toString() {
		return "Node2 [value=" + value + "]";
	}

	// 前序遍历
	public void preList() {
		System.out.println(this);
		if (this.left != null) {
			this.left.preList();
		}
		if (this.right != null) {
			this.right.preList();
		}
	}

	// 中序遍历
	public void infixList() {
		if (this.left != null) {
			this.left.infixList();
		}
		System.out.println(this);
		if (this.right != null) {
			this.right.infixList();
		}
	}

	// 以当前节点为根节点,求其树的高度
	public int height() {
		return Math.max(this.left == null ? 0 : this.left.height(), this.right == null ? 0 : this.right.height()) + 1;
	}

	// 求当前节点左子树的高度
	public int leftHeight() {
		if (this.left == null) {
			return 0;
		}
		return this.left.height();

	}

	// 求当前节点右子树的高度
	public int rightHeight() {
		if (this.right == null) {
			return 0;
		}
		return this.right.height();
	}

	/**
	 * 左旋转
	 */
	public void leftRotate() {
		// 1.以当前节点为根结点,创建一个新的节点,值为当前节点的值
		Node2 newNode = new Node2(this.value);
		// 2.将新节点的左子节点设置成当前节点的左子树
		newNode.left = this.left;
		// 3.将新节点的右子节点设置成当前节点右子节点的左子树
		newNode.right = this.right.left;
		// 4.将当前节点的值替换成其右子节点的值
		this.value = this.right.value;
		// 5.将当前节点的右子节点设置成当前节点右子节点的右子树
		this.right = this.right.right;
		// 6.将当前节点的左子节点设置成新节点
		this.left = newNode;
	}

	/**
	 * 右旋转
	 */
	public void rightRotate() {
		// 1.以当前节点为根节点,创建一个新的节点,值为当前节点的值
		Node2 newNode = new Node2(this.value);
		// 2.将新节点的右子节点设置成当前节点的右子树
		newNode.right = this.right;
		// 3.将新节点的左子节点设置成当前节点左子节点的右子树
		newNode.left = this.left.right;
		// 4.将当前节点的值替换成其左子节点的值
		this.value = this.left.value;
		// 5.将当前节点的左子节点设置成当前节点左子节点的左子树
		this.left = this.left.left;
		// 6.将当前节点的右子节点设置成新节点
		this.right = newNode;
	}

	/**
	 * 添加节点
	 * 
	 * @param node
	 */
	public void add(Node2 node) {
		if (node == null) {
			return;
		}
		// 如果要添加节点的值小于当前节点的值
		if (node.value < this.value) {
			// 如果当前节点的左子节点为空,那就直接挂上
			if (this.left == null) {
				this.left = node;
			} else {// 如果不为空,左递归
				this.left.add(node);
			}
		} else {// 如果要添加节点的值大于或等于当前节点的值
				// 如果当前节点的右子节点为空,那就直接挂上
			if (this.right == null) {
				this.right = node;
			} else {// 如果不为空,右递归
				this.right.add(node);
			}
		}

		// 节点添加完毕后,要开始判断是否是平衡二叉树,如果不是需要进行旋转操作
		// 1.如果当前节点的左子树高度-右子树高度>1,那么需要进行右旋转
		if (this.leftHeight() - this.rightHeight() > 1) {
			// !!!这里有种情况:如果以当前节点的左子节点为根节点,其右子树的高度>其左子树的高度时,需要局部进行左旋转。
			if (this.left != null && this.left.rightHeight() > this.left.leftHeight()) {
				// 以当前节点的左子节点为根节点,进行局部左旋转
				this.left.leftRotate();
			}
			// 然后以当前节点为根节点,进行右旋转
			this.rightRotate();
			// 旋转完就可以退出了
			return;
		}

		// 2.如果当前节点的右子树高度-左子树高度>1,那么需要进行左旋转
		if (this.rightHeight() - this.leftHeight() > 1) {
			// !!!这里有种情况:如果以当前节点的右子节点为根节点,其左子树的高度>其右子树的高度时,需要进行局部右旋转
			if (this.right != null && this.right.leftHeight() > this.right.rightHeight()) {
				// 以当前节点的右子节点为根结点,进行局部右旋转
				this.right.rightHeight();
			}
			// 然后以当前节点为根结点,进行左旋转
			this.leftRotate();
		}

	}

}

如有错误之处,还望指出,定会及时改正!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java中的平衡二叉树实现通常是基于红黑树算法,这是一种自平衡二叉查找树。在红黑树中,每个节点都被标记为红色或黑色,并满足以下特性: 1. 根节点是黑色的。 2. 所有叶子节点都是黑色的(叶子节点为NIL节点)。 3. 如果一个节点是红色的,则它的两个子节点都是黑色的。 4. 从任意节点到其每个叶子节点的所有路径都包含相同数目的黑色节点。 这些特性确保了红黑树是平衡的,因为任意路径上的黑色节点数目相同。插入和删除操作可以通过对颜色和结构进行适当的旋转来维护树的平衡性。 下面是一个简单的Java平衡二叉树实现示例: ``` import java.util.*; public class RedBlackTree<K extends Comparable<K>, V> { private static final boolean RED = true; private static final boolean BLACK = false; private Node root; private class Node { K key; V val; Node left, right; int size; boolean color; public Node(K key, V val, boolean color, int size) { this.key = key; this.val = val; this.color = color; this.size = size; } } private boolean isRed(Node x) { if (x == null) return false; return x.color == RED; } private int size(Node x) { if (x == null) return 0; return x.size; } public int size() { return size(root); } public boolean isEmpty() { return root == null; } public V get(K key) { if (key == null) throw new IllegalArgumentException("argument to get() is null"); return get(root, key); } private V get(Node x, K key) { while (x != null) { int cmp = key.compareTo(x.key); if (cmp < 0) x = x.left; else if (cmp > 0) x = x.right; else return x.val; } return null; } public boolean contains(K key) { return get(key) != null; } public void put(K key, V val) { if (key == null) throw new IllegalArgumentException("first argument to put() is null"); if (val == null) { delete(key); return; } root = put(root, key, val); root.color = BLACK; } private Node put(Node h, K key, V val) { if (h == null) return new Node(key, val, RED, 1); int cmp = key.compareTo(h.key); if (cmp < 0) h.left = put(h.left, key, val); else if (cmp > 0) h.right = put(h.right, key, val); else h.val = val; // fix-up any right-leaning links if (isRed(h.right) && !isRed(h.left)) h = rotateLeft(h); if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h); if (isRed(h.left) && isRed(h.right)) flipColors(h); h.size = size(h.left) + size(h.right) + 1; return h; } public void deleteMin() { if (isEmpty()) throw new NoSuchElementException("BST underflow"); // if both children of root are black, set root to red if (!isRed(root.left) && !isRed(root.right)) root.color = RED; root = deleteMin(root); if (!isEmpty()) root.color = BLACK; } private Node deleteMin(Node h) { if (h.left == null) return null; if (!isRed(h.left) && !isRed(h.left.left)) h = moveRedLeft(h); h.left = deleteMin(h.left); return balance(h); } public void deleteMax() { if (isEmpty()) throw new NoSuchElementException("BST underflow"); // if both children of root are black, set root to red if (!isRed(root.left) && !isRed(root.right)) root.color = RED; root = deleteMax(root); if (!isEmpty()) root.color = BLACK; } private Node deleteMax(Node h) { if (isRed(h.left)) h = rotateRight(h); if (h.right == null) return null; if (!isRed(h.right) && !isRed(h.right.left)) h = moveRedRight(h); h.right = deleteMax(h.right); return balance(h); } public void delete(K key) { if (key == null) throw new IllegalArgumentException("argument to delete() is null"); if (!contains(key)) return; // if both children of root are black, set root to red if (!isRed(root.left) && !isRed(root.right)) root.color = RED; root = delete(root, key); if (!isEmpty()) root.color = BLACK; } private Node delete(Node h, K key) { if (key.compareTo(h.key) < 0) { if (!isRed(h.left) && !isRed(h.left.left)) h = moveRedLeft(h); h.left = delete(h.left, key); } else { if (isRed(h.left)) h = rotateRight(h); if (key.compareTo(h.key) == 0 && (h.right == null)) return null; if (!isRed(h.right) && !isRed(h.right.left)) h = moveRedRight(h); if (key.compareTo(h.key) == 0) { Node x = min(h.right); h.key = x.key; h.val = x.val; h.right = deleteMin(h.right); } else h.right = delete(h.right, key); } return balance(h); } private Node rotateRight(Node h) { assert (h != null) && isRed(h.left); Node x = h.left; h.left = x.right; x.right = h; x.color = x.right.color; x.right.color = RED; x.size = h.size; h.size = size(h.left) + size(h.right) + 1; return x; } private Node rotateLeft(Node h) { assert (h != null) && isRed(h.right); Node x = h.right; h.right = x.left; x.left = h; x.color = x.left.color; x.left.color = RED; x.size = h.size; h.size = size(h.left) + size(h.right) + 1; return x; } private void flipColors(Node h) { assert !isRed(h) && isRed(h.left) && isRed(h.right); h.color = RED; h.left.color = BLACK; h.right.color = BLACK; } private Node moveRedLeft(Node h) { assert (h != null); assert isRed(h) && !isRed(h.left) && !isRed(h.left.left); flipColors(h); if (isRed(h.right.left)) { h.right = rotateRight(h.right); h = rotateLeft(h); flipColors(h); } return h; } private Node moveRedRight(Node h) { assert (h != null); assert isRed(h) && !isRed(h.right) && !isRed(h.right.left); flipColors(h); if (isRed(h.left.left)) { h = rotateRight(h); flipColors(h); } return h; } private Node balance(Node h) { assert (h != null); if (isRed(h.right)) h = rotateLeft(h); if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h); if (isRed(h.left) && isRed(h.right)) flipColors(h); h.size = size(h.left) + size(h.right) + 1; return h; } public K min() { if (isEmpty()) throw new NoSuchElementException("calls min() with empty symbol table"); return min(root).key; } private Node min(Node x) { if (x.left == null) return x; else return min(x.left); } public K max() { if (isEmpty()) throw new NoSuchElementException("calls max() with empty symbol table"); return max(root).key; } private Node max(Node x) { if (x.right == null) return x; else return max(x.right); } public Iterable<K> keys() { if (isEmpty()) return new LinkedList<K>(); return keys(min(), max()); } public Iterable<K> keys(K lo, K hi) { if (lo == null) throw new IllegalArgumentException("first argument to keys() is null"); if (hi == null) throw new IllegalArgumentException("second argument to keys() is null"); Queue<K> queue = new LinkedList<K>(); keys(root, queue, lo, hi); return queue; } private void keys(Node x, Queue<K> queue, K lo, K hi) { if (x == null) return; int cmplo = lo.compareTo(x.key); int cmphi = hi.compareTo(x.key); if (cmplo < 0) keys(x.left, queue, lo, hi); if (cmplo <= 0 && cmphi >= 0) queue.offer(x.key); if (cmphi > 0) keys(x.right, queue, lo, hi); } } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值