平衡二叉树——旋转与插入(Java 语言描述)

对平衡二叉树的研究,大概已有半年之久。最近才算是对它有所领悟。因为网上好多博文对其讲解的都很好,在此就不再详述,只对其进行分篇章总结。

一、左旋转

在网上找到一左转GIF示意图。我借用一下:

在不平衡子树的右子树的右孩子插入结点导致的不平衡应该进行左旋转。

    /**
	 * 约定null节点的高度为-1, 叶子结点高度为0。到根结点变大;
	 * @param node 某一节点引用;
	 * @return
	 */
	private int _height(AVLNode<T> node) {
		return node == null ? -1 : node.height;
	}

	/**
	 * 逆时针单旋转;
	 * @param parent
	 * @return
	 */
	private AVLNode<T> _leftRotation(AVLNode<T> w) {
		AVLNode<T> x = w.rChild;
		w.rChild = x.lChild;
		x.lChild = w;
		
		w.height = Math.max(_height(w.lChild), _height(w.rChild)) + 1;
		x.height = Math.max(w.height, _height(x.rChild)) + 1;
		
		return x;
	}

二、右旋转

右旋转与左旋转是镜像的如下:

在不平衡子树的左子树的左孩子插入结点导致的不平衡应该进行右旋转。 

	private AVLNode<T> _rightRotation(AVLNode<T> x) {
		AVLNode<T> w = x.lChild;
		x.lChild = w.rChild;
		w.rChild = x;
		
		x.height = Math.max(_height(x.lChild), _height(x.rChild)) + 1;
		w.height = Math.max(x.height, _height(w.lChild)) + 1;
		
		return w;
	}

三、左右旋转

假如在不平子树根节点的左子树的右子树插入结点导致的不平衡。则先对根结点左子树旋转,再右转不平衡子树。

	// lr
	private AVLNode<T> _left_right_ratation(AVLNode<T> p) {
		p.lChild = _leftRotation(p.lChild);
		return _rightRotation(p);
	}

四、右左旋转

假如在不平衡子树根节点的右子树的左子树插入结点导致的不平衡。则先对根节点的右子树旋转,再对不平衡子树根结点旋转。

	private AVLNode<T> _right_left_ratation(AVLNode<T> p) {
		p.rChild = _rightRotation(p.rChild);
		return _leftRotation(p);
	}

五、插入元素

插入后要沿着递归插入的路径回溯(出栈), 利用此性质对结点的平衡因子检查。如需旋转根据情况旋转,并刷新其高度。

	private AVLNode<T> _insert(AVLNode<T> parent, T data) {
		if (parent == null) {
			parent = new AVLNode<T>(data);
		}
		
		int result = data.compareTo(parent.data);
		
		if (result < 0) {
			parent.lChild = _insert(parent.lChild, data);
			if (_height(parent.lChild) - _height(parent.rChild) == 2) {
				if (data.compareTo(parent.lChild.data) < 0) {
					parent = _rightRotation(parent);
				} else {
					parent = _left_right_ratation(parent);
				}
			}
		} else if (result > 0) {
			parent.rChild = _insert(parent.rChild, data);
			if (_height(parent.rChild) - _height(parent.lChild) == 2) {
				if (data.compareTo(parent.rChild.data) > 0) {
					parent = _leftRotation(parent);
				} else {
					parent = _right_left_ratation(parent);
				}
			}
		} else {
			// do nothing;
		}
		
		parent.height = Math.max(_height(parent.lChild), _height(parent.rChild)) + 1;
		
		return parent;
	}

完整代码:

public class AVLNode<T extends Comparable> {
	public T 			data;
	public int 			height;
	public AVLNode<T> 	lChild;
	public AVLNode<T> 	rChild;
	
	public AVLNode(T data, int height ,AVLNode<T> lChild, AVLNode<T> rChild) {
		this.data   = data;
		this.height = height;
		this.lChild = lChild;
		this.rChild = rChild;
	}
	
	// 委托构造;
	public AVLNode(T data, AVLNode<T> lChild, AVLNode<T> rChild) {
		this(data, 0, lChild, rChild);
	}
	
	// 委托构造;
	public AVLNode(T data) {
		this(data, null, null);
	}
}

public class AVLDTree<T extends Comparable> implements Tree<T> {
	private AVLNode<T> root;
	
	
	@Override
	public int height() {
		return _height(root);
	}


	@Override
	public void insert(T value) {
		if (value == null) {
			throw new RuntimeException("data null");
		}
		
		this.root = _insert(root, value);
	}


	/**
	 * 约定null节点的高度为-1, 叶子结点高度为0。到根结点变大;
	 * @param node 某一节点引用;
	 * @return
	 */
	private int _height(AVLNode<T> node) {
		return node == null ? -1 : node.height;
	}
	
	/**
	 * 逆时针单旋转;
	 * @param parent
	 * @return
	 */
	private AVLNode<T> _leftRotation(AVLNode<T> w) {
		AVLNode<T> x = w.rChild;
		w.rChild = x.lChild;
		x.lChild = w;
		
		w.height = Math.max(_height(w.lChild), _height(w.rChild)) + 1;
		x.height = Math.max(w.height, _height(x.rChild)) + 1;
		
		return x;
	}
	
	private AVLNode<T> _rightRotation(AVLNode<T> x) {
		AVLNode<T> w = x.lChild;
		x.lChild = w.rChild;
		w.rChild = x;
		
		x.height = Math.max(_height(x.lChild), _height(x.rChild)) + 1;
		w.height = Math.max(x.height, _height(w.lChild)) + 1;
		
		return w;
	}
	
	// lr
	private AVLNode<T> _left_right_ratation(AVLNode<T> p) {
		p.lChild = _leftRotation(p.lChild);
		return _rightRotation(p);
	}
	
	private AVLNode<T> _right_left_ratation(AVLNode<T> p) {
		p.rChild = _rightRotation(p.rChild);
		return _leftRotation(p);
	}

	private AVLNode<T> _insert(AVLNode<T> parent, T data) {
		if (parent == null) {
			parent = new AVLNode<T>(data);
		}
		
		int result = data.compareTo(parent.data);
		
		if (result < 0) {
			parent.lChild = _insert(parent.lChild, data);
			if (_height(parent.lChild) - _height(parent.rChild) == 2) {
				if (data.compareTo(parent.lChild.data) < 0) {
					parent = _rightRotation(parent);
				} else {
					parent = _left_right_ratation(parent);
				}
			}
		} else if (result > 0) {
			parent.rChild = _insert(parent.rChild, data);
			if (_height(parent.rChild) - _height(parent.lChild) == 2) {
				if (data.compareTo(parent.rChild.data) > 0) {
					parent = _leftRotation(parent);
				} else {
					parent = _right_left_ratation(parent);
				}
			}
		} else {
			// do nothing;
		}
		
		parent.height = Math.max(_height(parent.lChild), _height(parent.rChild)) + 1;
		
		return parent;
	}
}

public class Main {

	public static void main(String[] args) {
		AVLDTree<Integer> avlT = new AVLDTree<Integer>();
		avlT.insert(3);
		avlT.insert(2);
		avlT.insert(1);
		avlT.insert(4);
		avlT.insert(5);
		avlT.insert(6);
		avlT.insert(7);
		avlT.insert(10);
		avlT.insert(9);
		avlT.insert(8);
	}
}

还没有写遍历代码,但可以通过debug来查看树插入数据后的内存情况。中序遍历结果应该是这样:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值