为了提高二插排序树的性能,规定树中的每个节点的左子树和右子树高度差的绝对值不能大于1。为了满足上面的要求需要在插入完成后对树进行调整。下面介绍各个调整方式。
右单旋转如下图所示,节点A的平衡因子(左子树高度减右子树高度)为1。由于在节点A的左孩子B的左子树上插入了新节点,导致B的左子树高度增加1,从而导致A的平衡因子为2,这时为了保持平衡需要对树进行调整。
旋转的方法就是将A的变为B的右子树,将B的右子树变为A的左子树。
示例代码:
private Node RRotate(Node node){
Node A= node;
Node B= node.LChild;
//旋转
Node tmp = B.RChild;
B.RChild= A;
A.LChild= tmp;
//更新树的高度
A.height = Math.max(height(A.LChild), height(A.RChild))+1;
B.height= Math.max(height(B.LChild), height(B.RChild))+1;
return B;
}
(每个节点我们维护了一个height的属性来记录树的高度,每次旋转完成后需要更新树的高度。因为旋转会导致书的根节点发生变化,所以每次旋转完成后需要将新的根节点返回)
左单旋转左单旋转整好与右单旋转相反。右单旋转是因为左子树太高,而左单旋转则是因为右子树太高,需要降低其高度。
如图所示节点B的右子树高度增加1,导致节点A的平衡因子变为-2,所以需要进行左旋调整位置。
旋转方法:将A变为B的左子树,将B的左子树变为A的右子树
示例代码:
private Node LRotate(Node node){
Node A= node;
Node B= node.RChild;
//旋转
Node tmp = B.LChild;
B.LChild= A;
A.RChild= tmp;
//更新树的高度
A.height = Math.max(height(A.LChild), height(A.RChild))+1;
B.height= Math.max(height(B.LChild), height(B.RChild))+1;
return B;
}
(每个节点我们维护了一个height的属性来记录树的高度,每次旋转完成后需要更新树的高度。因为旋转会导致书的根节点发生变化,所以每次旋转完成后需要将新的根节点返回)
先左后右旋转上面的两种情况处理比较简单,因为插入的节点要么是根节点左孩子的左子树或者是根节点右孩子的右子树。如果插入的节点在根节点左孩子的右子树上,则需要先进行左旋然后进行右旋操作。
如图所示,插入的节点在B节点右子树上,这时需要对B节点进行左旋操作,然后对A节点进行右旋操作。
示例代码:
private Node LRRotate(Node node){
//先进行左旋
LRotate(node.LChild);
//在进行右旋
return RRotate(node);
}
代码中node节点就是图中的A节点,先对A节点的左孩子B进行左旋操作,然后对A(node)节点进行右旋操作
先右旋后左旋当插入的节点在根节点的右孩子的左子树上,则需要进行先右旋后左旋操作。
示例代码: