我个人是通过b站学习的懂得
b站视频连接:
https://www.bilibili.com/video/av37955102?from=search&seid=14638889623357631324
https://www.bilibili.com/video/av37955178?from=search&seid=14638889623357631324
https://www.bilibili.com/video/av37955231?from=search&seid=14638889623357631324
旋转原则:
下面看一张图:
PS: 以下 p 是A q是B
LL型:
1) 定义一个结构体指针指向A的左子树 ,tree *q = p->l
2) 让A左子树连上B的右子树 p->l = q->r (因为B是A的左子树, 所以B上所有子节点的data 都小于A 的data) ,
3) 由于A的data大于B的data ,再将B的右子树连上A q->r = p
3) 计算q的(B)右子树p深度 p->height = max(height(p->l), height(p->r)) + 1; // +1 是加上p本身
4) 计算q的深度 q->height = max(height(q->l), p->height) + 1; // +1 是加上q本身
RR型:
1) 定义一个结构体指针指向A的右子树 ,tree *q = p->r
2) 让A右子树连上B的左子树 p->l = q->r (因为B是A的右子树, 所以B上所有子节点的data 都大于A 的data) ,
3) 由于A的data小于B的data ,再将B的左子树连上A q->l = p
3) 计算q的(B)左子树p深度 p->height = max(height(p->l), height(p->r)) + 1; // +1 是加上p本身
4) 计算q的深度 q->height = max(height(q->l), p->height) + 1; // +1 是加上q本身
LR型:
一次RR 一次LL
RL型:
一次LL 一次RR
下面是一个例题:
数据结构实验之查找二:平衡二叉树
Time Limit: 400 ms Memory Limit: 65536 KiB
Problem Description
根据给定的输入序列建立一棵平衡二叉树,求出建立的平衡二叉树的树根。
Input
输入一组测试数据。数据的第1行给出一个正整数N(n <= 20),N表示输入序列的元素个数;第2行给出N个正整数,按数据给定顺序建立平衡二叉树。
Output
输出平衡二叉树的树根。
Sample Input
5 88 70 61 96 120
Sample Output
70
Hint
Source
xam
ACcode:
#include <bits/stdc++.h>
using namespace std;
struct tree
{
int data; //记录关键字数值
tree *l, *r;
int height; //平衡因子
};
int height(tree *p) //求树的深度
{
if (p == NULL)
return -1;
return p->height;
}
tree *LL(tree *p) //对LL型直接在不平衡结点进行左旋转
{
tree *q;
q = p->l; // q是p的左子树
p->l = q->r; // q的左子树一定小于p->data 所以p->l连上q->r
q->r = p; // q->r连上p
p->height = max(height(p->l), height(p->r)) + 1; // 结点的位置变了,要更新结点的高度值
q->height = max(height(q->l), p->height) + 1;
return q;
}
tree *RR(tree *p) //对RR型直接在不平衡结点进行右旋转
{
tree *q; // 连接原理与LL相同
q = p->r;
p->r = q->l;
q->l = p;
p->height = max(height(p->l), height(p->r)) + 1;
q->height = max(height(q->r), p->height) + 1;
return q;
}
tree *LR(tree *p)
{
p->l = RR(p->l); //在不平衡结点p的左儿子处进行右旋转
return LL(p); //在不平衡结点p处进行左旋转并返回新的根
}
tree *RL(tree *p)
{
p->r = LL(p->r); //在不平衡结点p的右儿子处进行左旋转
return RR(p); //在不平衡结点p处进行左旋转并返回新的根
}
tree *insert(tree *p, int k)
{
if (p == NULL) //待插入的值赋给新开辟的结点
{
p = new tree;
p->data = k;
p->height = 0;
p->l = p->r = NULL;
}
else if (k < p->data) //若待插入的值小于p的关键字数值,则插入到左子树中
{
p->l = insert(p->l, k);
if (height(p->l) - height(p->r) == 2) //该树出现不平衡
{
if (k < p->l->data) //若待插入的值插到了左儿子的左子树上则单旋转
p = LL(p);
else //反之,双旋转
p = LR(p);
}
}
else if (k > p->data) //道理同上
{
p->r = insert(p->r, k);
if (height(p->l) - height(p->r) == -2)
{
if (k > p->r->data)
p = RR(p);
else
p = RL(p);
}
}
p->height = max(height(p->l), height(p->r)) + 1;
return p;
}
int main()
{
int n, k;
while (cin >> n)
{
tree *head = NULL;
for (int i = 0; i < n; i++)
{
cin >> k;
head = insert(head, k);
}
cout << head->data << endl;
}
return 0;
}
/***************************************************
User name: QXQZX
Result: Accepted
Take time: 0ms
Take Memory: 236KB
Submit time: 2018-12-19 14:58:13
****************************************************/