![eb01bca897b0407d0b11fe0d89388b87.png](https://i-blog.csdnimg.cn/blog_migrate/e986f80a386eb094bdcfd54a9bf207ad.png)
再讲avl树之前我们要先了解什么是二叉查找树。
二叉查找树:
![f00480ef70c140eed5eabe06c37571d5.png](https://i-blog.csdnimg.cn/blog_migrate/ca6d99f62d64e333b66ee4e94a17b40f.png)
如图为二叉查找树:
1.左子树的所有节点小于根节点
2.右子树的所有节点大于根节点
3.左右子树均为二叉查找树
关于二叉查找树的创建可以参考下面这个文章:
夜猫子:二叉查找树的创建和基本操作—c语言zhuanlan.zhihu.com![9d63838509834e2864362a0d080a765f.png](https://i-blog.csdnimg.cn/blog_migrate/d2184d819367eedec724a829dc46a4a8.png)
引入avl树的原因:二叉查找树的特点就是能够快速查找数据,如上图,若查找2,则从左子树开始查找,若查找8,则从右子树查找。所以说,二叉查找树的时间复杂度一般情况下为O(logN)。但是如果发生以下情况:
![9ba3b44229c481c0dac57e45480f569a.png](https://i-blog.csdnimg.cn/blog_migrate/5ac21047393f8e159f98183763bf32c0.png)
如果想要查1的话,原来的二叉树查找就变为了链表表即线性的查找,时间复杂度就变为O(oN),所以为了在特殊情况下仍保持O(logN)的时间复杂度,我们需要将树变换,我们引入了avl树。
avl树:
![ec8db7f4e79ef9223508854914a6af5e.png](https://i-blog.csdnimg.cn/blog_migrate/d8de46eb11eed9c7608e02a26a110280.png)
如图,根节点5的深度为-1,则左子树的深度为2,右子树的深度为1
avl树的特点:
1.每个节点的左右子树深度都相差1或0.
2.具有二查找树的全部特点
如图,该数不是avl树,左右子树:
![2c8f0618d9cf7c9eab4d3e74870cc9d0.png](https://i-blog.csdnimg.cn/blog_migrate/cbabe1ae8be9f6fc06498847608a5d84.png)
结点为5的树不平衡,左右深度差为2
![62412f080bf53b03e1220372c9b4d079.png](https://i-blog.csdnimg.cn/blog_migrate/798822c18f458d18388718874cb34a83.png)
结点为8的树不平衡,左右深度相差为2,不是avl树。
avl树的创建:
- 单旋:
1.左儿子的左子树插入(左左)——右旋
![0ababfe44703198570813a4b830612cf.png](https://i-blog.csdnimg.cn/blog_migrate/9fac2f65211e4a6f73142545ea31ee46.jpeg)
2.右儿子的右子树插入(右有)——左旋
![424d7cc2a1a5b86e0a7204473cc7f419.png](https://i-blog.csdnimg.cn/blog_migrate/232cb8b258e378fa491844bcdebfaa2b.jpeg)
- 双旋:
1.右儿子的左子树插入(右左)——先右旋再左旋
![1a6bc969729fdb7233fc3f03bffaf6e3.png](https://i-blog.csdnimg.cn/blog_migrate/cea5874b563bfcf7ad46cafb887d9a97.jpeg)
如图,6为失衡点,在右儿子(9)的右子树(8)插入节点5,所以两次旋转,先右旋在左旋
2.左儿子的右子树插入(左右)——先左旋再右旋
![32bb4ae2ecd3ea379930c1e416a5957d.png](https://i-blog.csdnimg.cn/blog_migrate/90187f22ca46c825d4c8c743258c94d6.jpeg)
如图,7为失衡点,在左儿子(3)的右子树(4)插入节点5,所以两次旋转,先左旋在右旋
总结:
判断是单旋还是双旋,要先确定失衡点,确定失衡点后四种情况来确定单旋还是双旋
代码实现(递归):
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10
typedef struct TreeNode* Position;
typedef struct TreeNode* AvlTree;
typedef struct TreeNode* SearchTree;
Position Find(int x, AvlTree T);
typedef struct TreeNode {
AvlTree left;
AvlTree right;
int Height;
int data;
}*Bintree;
Bintree InitTree(int x, AvlTree T);//创建二叉查找树
Bintree InitAvlTree(int x, SearchTree T);//创建avl树
//max和height函数用来计算树高
int Max(int T1, int T2) {
return T1 >= T2 ? T1 : T2;
}
int Height(AvlTree T) {
if (T == NULL)
return -1;
else
return T->Height;
}
//右旋
Position SingleRotateWithRight(AvlTree K2) {
Position K1;
K1=K2->left;
K2->left = K1->right;
K1->right = K2;
K2->Height = Max(Height(K2->left), Height(K2->right)) + 1;
K1->Height = Max(Height(K1->left), K2->Height);//更新树的高度
return K1;
}
//左旋
Position SingleRotateWithLeft(AvlTree K2) {
Position K1;
K1 = K2->right;
K2->right = K1->left;
K1->left= K2;
K2->Height = Max(Height(K2->left), Height(K2->right)) + 1;
K1->Height = Max(Height(K1->right), K2->Height);//更新树的高度
return K1;
}
//双旋:先左旋再右旋
Position DoubleRotateWithLeftAndRight(AvlTree K3) {
K3->left = SingleRotateWithLeft(K3->left);
return SingleRotateWithRight(K3);
}
//双旋:先右旋再左旋
Position DoubleRotateWithRightAndLeft(AvlTree K3) {
K3->right = SingleRotateWithRight(K3->right);
return SingleRotateWithLeft(K3);
}
//构造二叉查找树树
Bintree InitTree(int x, SearchTree T) {
int i = 0;
if (T == NULL) {
T = (Bintree)malloc(sizeof(struct TreeNode));
if (T == NULL)
return 0;
else {
T->data = x;
T->right = NULL;//先右节点,在左节点
T->left = NULL;
}
}
else if (x < T->data) {
T->left = InitTree(x, T->left);
}
else if (x > T->data) {
T->right = InitTree(x, T->right);
}
else
printf("%d has insertedn", x);
return T;
}
//构造avl树
Bintree InitAvlTree(int x, AvlTree T) {
int i = 0;
if (T == NULL) {
T = (Bintree)malloc(sizeof(struct TreeNode));
if (T == NULL)
return 0;
else {
T->data = x;
T->right = NULL;
T->left = NULL;
T->Height = 0;
}
}
else if (x < T->data) {
T->left = InitAvlTree(x, T->left);//插入节点过程
if (Height(T->left) - Height(T->right) == 2) {//是否旋转的条件判断
if (x < T->left->data)//左左情况单旋
T = SingleRotateWithRight(T);//进行右旋
else//左右情况双旋:先左旋再右旋
T = DoubleRotateWithLeftAndRight(T);//Left表示左右情况
}
}
else if (x > T->data) {//右右和右左情况
T->right = InitAvlTree(x, T->right);
if (Height(T->right) - Height(T->left) == 2) {
if (x > T->right->data)
T = SingleRotateWithLeft(T);
else
T = DoubleRotateWithRightAndLeft(T);
}
}
else
printf("%d has inserted,we'll do nothingn", x);
T->Height = Max(Height(T->left), Height(T->right))+1;//计算高度
return T;
}
//先序遍历
void Preorder(Bintree p)
{
if (p != NULL)
{
printf("%dt", p->data);
Preorder(p->left);
Preorder(p->right);
}
}
//中序遍历
void Inorder(Bintree p)
{
if (p != NULL)
{
Inorder(p->left);
printf("%dt", p->data);
Inorder(p->right);
}
}
//后序遍历
void Postorder(Bintree p)
{
if (p != NULL)
{
Postorder(p->left);
Postorder(p->right);
printf("%dt", p->data);
}
}
int main() {//为了方便观察主函数写的较为冗余
Bintree p1 = NULL,p2=NULL;
int a[MaxSize],num;
printf("scanf element number:");
scanf_s("%d", &num);
printf("scanf element:");
for (int i = 0; i < num; i++) {
scanf_s("%d", &a[i]);
p1= InitTree(a[i], p1);
p2 = InitAvlTree(a[i], p2);
}
printf("Preorder is:");//先序遍历
Preorder(p1);
printf("n");
printf("Inorder is:");//中序遍历
Inorder(p1);
printf("n");
printf("Postorder is:");//后序遍历
Postorder(p1);
printf("n");
printf("avltree:n");//改进后avl树
printf("Preorder is:");//先序遍历
Preorder(p2);
printf("n");
printf("Inorder is:");//中序遍历
Inorder(p2);
printf("n");
printf("Postorder is:");//后序遍历
Postorder(p2);
printf("n");
return 0;
}
代码测试:
单旋:
![882b7a5d71042b091d15090a66d5749c.png](https://i-blog.csdnimg.cn/blog_migrate/8c39e9887270ca3a5f92819c3c4ae95e.jpeg)
![4e53277c855bd0a781dd94e1f032a880.png](https://i-blog.csdnimg.cn/blog_migrate/6dcafd6338072d1584fcb6e4eb2e3afb.png)
![a4e881ec32880f0b28f0b83ce72640ec.png](https://i-blog.csdnimg.cn/blog_migrate/7e353d7cf774128a0ca5bd9f37a3100b.png)
测试结果与预算结果相同,单旋测试成功
双旋:
![b9f1ef837b4b5d4adbe7fba92280a8fc.png](https://i-blog.csdnimg.cn/blog_migrate/9cad7d09bddc6f3f8e0d75a82bc26841.jpeg)
![f01418d4915e1177bcf0600cd2e692fe.png](https://i-blog.csdnimg.cn/blog_migrate/87ec0ab4f49476edd57a0b5e4c9ba840.png)
![d8653853c11e689d33e5d69ca3d2487e.png](https://i-blog.csdnimg.cn/blog_migrate/555e112cff2c408143930742dc786263.png)
与预期结果相同,测试成功