本文要点:
平衡搜索树的左单旋、右单旋、左右双旋、右左双旋
在平衡搜索树中进行插入结点时,有可能会破坏整棵树的平衡。为了保证平衡不被破坏,就要对一些节点进行旋转,从而来降低树的高度,这样也能保证树的平衡。
一、左单旋:
(上图中的▲结点有可能是NULL,也有可能不为空。。。下同)
从图中可以看出,进行左单旋时,只是改变了parent的右指针以及subR的左指针指向。将subR的左子树(subRL)作为parent的右子树,并让parent作为subR的左子树。很明显,这样做就降低了这棵树的高度。
进行旋转时需要注意的两点:
1.改变subRL->_parent指向时,需要判断subRL是否为NULL,如果为空,就不能对其解引用。
2.parent是否为根节点?如果parent为根节点,那么旋转完成后只需将subR赋给根节点即可;但如果parent不为根节点,即parent是某一节点ppNode的子树,就要判断parent在ppNode的左还是右,这样才能确定subR的位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
void
RotateLeft(Node* parent)
//左单旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
//先改变parent的右指针
if
(subRL)
//subRL可能为NULL
{
subRL->_parent = parent;
}
Node* ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if
(ppNode == NULL)
{
_root = subR;
subR->_parent = NULL;
}
else
{
//判断subR应链接在ppNode的左子树还是右子树
if
(ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
}
|
二、右单旋:
同左单旋一样,右单旋转是将subL的右子树结点赋给parent的左指针,并让parent自己作为subL的右子树。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
void
RotateRight(Node* parent)
//右单旋
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if
(subLR)
{
subLR->_parent = parent;
}
Node* ppNode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if
(ppNode == NULL)
//说明parent结点为根节点
{
_root = subL;
subL->_parent = NULL;
}
else
{
//如果parent不为根节点,判断其在上一个结点的右还是左
if
(ppNode->_left == parent)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
}
|
三、左右双旋:
了解了单旋之后,双旋就比较简单,只是进行了两步单旋而已
1
2
3
4
5
6
|
void
RotateLR(Node* parent)
//左右双旋
{
RotateLeft(parent->_left);
RotateRight(parent);
}
|
1
2
3
4
5
6
7
|
void
RotateRL(Node* parent)
//右左双旋
{
RotateRight(parent->_right);
RotateLeft(parent);
}
|