先介简单的绍一下排序二叉树:对树中的每个节点都满足:节点左子树的每个节点都小于节点自身,节点右子树的每个节点都大与节点自身
AVL 树的全称应该称作 “AVL 平衡二叉排序树” 一棵AVL平衡二叉排序树满足每个节点的平衡因子(左子树的深度减右子树的深度)都在-1到1之间
AVL平衡二叉排序树 的核心思想就是,根据平衡因子进行旋转平衡,因为一棵非平衡的子树经过旋转之后必然平衡,就这样一层一层的向上旋转直到不再需要旋转或者到达了根节点,整棵树就恢复了平衡,无论如何插入删除都能够恢复平衡
在进入正题前先看个树的插入删除操作(如下图)
插入在55的右边插入83后进行左旋再次平衡
xxxxxxxxxxxxxxxxxx Begin
22
0 37
55
xxxxxxxxxxxxxxxxxx End
Insert complete
xxxxxxxxxxxxxxxxxx Begin
22
0 55
37 83
xxxxxxxxxxxxxxxxxx End
Insert complete
设计思路
AVL树的 平衡因子 指的是 左子树深度 减 右子树深度 的差值
作为AVL平衡二叉排序树,只要满足每个节点的平衡因子都在-1到1之间,就是一棵平衡二叉树
假设有平衡二叉树(见下图),其中 D 的父节点省略未写(也就是说 D 不是根节点),
下面<>括号中是节点对应的平衡因子,问号代表平衡因子在-1到1之间,()括号中是节点对应的深度
// 以下是 AVL 平衡二叉树由于插入或删除导致失去平衡的种情况的其中最典型的几种,这里 A,C 和 E 的子树都省略不写
// 失去平衡的第一种情况
D<1>(h+3)
B<0>(h+2) E<?>(h)
A<?>(h+1) C<?>(h+1) 省略 省略
// 失去平衡的第二种情况
D<1>(h+3)
B<1>(h+2) E<?>(h)
A<?>(h+1) C<?>(h) 省略 省略
// 失去平衡的第三种情况
D<1>(h+3)
B<-1>(h+2) E<?>(h)
A<?>(h) C<?>(h+1) 省略 省略
// 这里省略对称的情况(即 E 节点在左边的情况)
// 对于情况一A(h+1)和C(h+1)深度相等时,要恢复平衡需要进行右旋操作,如下
B<-1>(h+3)
A<?>(h+1) D<1>(h+2)
省略 省略 C<?>(h+1) E<?>(h)
// 如上,旋转之后每个节点都恢复了平衡,且子树的深度和旋转前的子树深度一致都为 h+3,因此不需要再对 B<0>(h+3) 的父节点进行调整
// 对于情况二A(h+1)和C(h)深度不等时,要恢复平衡需要进行右旋操作,如下
B<0>(h+2)
A<?>(h+1) D<0>(h+1)
省略 省略 C<?>(h) E<?>(h)
// 可以看出这里与情况一不同,子树B<0>(h+2)的深度减了1,由原本的h+3降为了h+2,因此我们需要对 B 节点的父节点进行更新,判断是否需要进行旋转,
<情况2_1>当 B 与兄弟节点的深度一样时(即B的父节点的平衡因子为0)只需要更新父节点的平衡因子即可(因为父节点既未失去平衡,深度也没变化),
<情况2_2>更新B父节点之后未失去平衡,但时B父节点的深度降了一层,这时需要向上继续更新B父节点的父节点
<情况2_3>更新B父节点之后失去了平衡,需要对B的父节点进行左旋转
// 对于情况三A(h)和C(h+1)深度不等时,需要对B节点先进行一次左旋转,之后再对D节点像情况二一样的进行右旋转,
// 对于B进行左旋并不会使得B节点失去平衡或改变B节点的深度(详细这里就不证明了),仅仅是为了后续D节点的右旋转做准备(防止旋转后还是未平衡)
对于删除操作,这里分为三种情况: 删除节点没有子节点,删除节点有一个子节点,删除节点有两个子节点
第一种情况:删除节点没有子节点
当删除节点的父节点更新平衡因子之后平衡因子为 -1或1时(可以想象一下是什么样的情况),删除节点并不会降父节点子树高度,因此只需要更新平衡因子,将对应链接置为NULL
当删除节点的父节点更新平衡因子之后平衡因子为 0时(可以想象一下是什么样的情况),说明父节点子树降低了一层我们需要调用函数进行平衡操作
当删除节点的父节点更新平衡因子之后平衡因子为-2或2时(可以想象一下是什么样的情况),我们需要先对父节点进行旋转,如果旋转后降低了一层我们就需要进行后续的平衡工作
第二种情况,删除节点有一个子节点
这种情况父节点子树必然降低一层,我们需要先将删除节点的子节点链接到删除节点的父节点,再更新删除节点的父节点的平衡因子,根据删除节点的父节点平衡因子判断是否需要进行旋平衡
第二种情况,删除节点有两个子节点
这种情况我们可以转换为第一第二种情况,我们只需要找到删除节点右子树的最大元素,与删除节点进行替换,从而转换成了第一第二种情况
AVLtree_c 文件
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "Queue.h"
#define TRACE(tree, info) PrintByLevel(tree);printf("%s\n", info);
int g_traceStep = 0; // 断点调试时作为触发断点的条件
struct Node {
int data;
int deep;
int distanceToTop; // 辅助测试(深度从上大下增大)
int posAtTree; // 辅助测试(从左到右从上大下)
// 平衡因子:左子树深度减右子树深度(AVL平衡二叉树每个节点的balance值都在-1到1之间)
int balance;
struct Node * parent;
struct Node * left;
struct Node * right;
};
struct AVLtree {
struct Node top;
};
void UpdateDeep(struct AVLtree * tree);
void PrintByLevel(struct AVLtree * tree);
//-------------------------------Init--------------------------------------
void InitAVLtree(struct AVLtree * tree) {
tree->top.parent = NULL;
tree->top.left = NULL;
tree->top.right = NULL;
}
//-------------------------------Destroy------------------------------------
void DestroyNode(struct Node * node) {
if(node == NULL) return;
DestroyNode(node->left);
DestroyNode(node->right);
free(node);
}
void DestroyAVLtree(struct AVLtree * tree) {
DestroyNode(tree->top.parent);
}
int RotateRight(struct AVLtree * tree, struct Node * node);
int UpdateBalanceL(struct Node * node);
//-------------------------------RotateLeft-------------------------------
int RotateLeft(struct AVLtree * tree, struct Node * node) {
struct Node * parent = node->parent;
struct Node * right = node->right;
int rightBalance = right->balance;
if(rightBalance == 1) {
RotateRight(tree, right);
right = node->right;
}
int isDecreaseLevel = UpdateBalanceL(node);
if(node == tree->top.parent)
tree->top.parent = right;
else if(parent->right == node)
parent->right = right;
else
parent->left = right;
right->parent = parent;
node->right = right->left;
if(right->left != NULL)
right->left->parent = node;
right->left = node;
node->parent = right;
// 返回-1表示旋转后减少一层
return isDecreaseLevel;
}
int UpdateBalanceL(struct Node * node) {
struct Node * right = node->right;
int decreaseLevel = 0;
if(node->left != NULL) {
if(right->left == NULL) {
node->balance = 1;
right->balance = 1;
} else if(node->balance == -2) {
if(right->balance == -1) {
node->balance = 0;
right->balance = 0;
decreaseLevel = -1;
} else {
node->balance = -1;
right->balance = 1;
}
} else {
if(right->balance == 0)
node->balance = 0;
else {
node->balance = 1;
decreaseLevel = -1;
}
right->balance = 1;
}
} else {
if(right->right == NULL) {
node->balance = 0;
right->balance = 1;
} else if(right->left == NULL) {
node->balance = 0;
right->balance = 0;
decreaseLevel = -1;
} else {
node->balance = -1;
right->balance = 1;
}
}
return decreaseLevel;
}
int UpdateBalanceR(struct Node * node);
//-------------------------------RotateRight------------------------------
int RotateRight(struct AVLtree * tree, struct Node * node) {
struct Node * parent = node->parent;
struct Node * left = node->left;
int leftBalance = left->balance;
if(leftBalance == -1) {
RotateLeft(tree, left);
left = node->left;
leftBalance = left->balance;
}
int isDecreaseLevel = UpdateBalanceR(node);
if(node == tree->top.parent)
tree->top.parent = left;
else if(parent->left == node)
parent->left = left;
else
parent->right = left;
left->parent = parent;
node->left = left->right;
if(left->right != NULL)
left->right->parent = node;
left->right = node;
node->parent = left;
// 返回-1表示旋转后减少一层
return isDecreaseLevel;
}
int UpdateBalanceR(struct Node * node) {
struct Node * left = node->left;
int decreaseLevel = 0;
if(node->right != NULL) {
if(left->right == NULL) {
node->balance = -1;
left->balance = -1;
} else if(node->balance == 2) {
if(left->balance == 1) {
node->balance = 0;
left->balance = 0;
decreaseLevel = -1;
} else {
node->balance = 1;
left->balance = -1;
}
} else {
if(left->balance == 0) {
node->balance = 0;
} else {
node->balance = -1;
decreaseLevel = -1;
}
left->balance = -1;
}
} else {
if(left->left == NULL) {
node->balance = 0;
left->balance = -1;
} else if(left->right == NULL) {
node->balance = 0;
left->balance = 0;
decreaseLevel = -1;
} else {
node->balance = 1;
left->balance = -1;
}
}
return decreaseLevel;
}
//-------------------------------BalanceInsert--------------------------------
void BalanceInsert(struct AVLtree * tree, struct Node * node) {
struct Node * parent;
while (node != tree->top.parent) {
parent = node->parent;
if(node == parent->left)
parent->balance += 1;
else
parent->balance -= 1;
if (parent->balance == 0) {
break;
} else if (parent->balance == -2) {
if(RotateLeft(tree, parent) == -1) return;
parent = node->parent;
} else if (parent->balance == 2) {
if(RotateRight(tree, parent) == -1) return;
parent = node->parent;
}
if(parent == NULL) break;
node = parent;
}
}
//-------------------------------BalanceErase--------------------------------
void BalanceErase(struct AVLtree * tree, struct Node * node) {
struct Node * parent;
while (node != tree->top.parent) {
parent = node->parent;
if(node == parent->left)
parent->balance -= 1;
else
parent->balance += 1;
if (parent->balance == 1 || parent->balance == -1) {
break;
} else if (parent->balance == -2) {
if(RotateLeft(tree, parent) == 0)
return;
parent = parent->parent;
} else if (parent->balance == 2) {
if(RotateRight(tree, parent) == 0)
return;
parent = parent->parent;
}
node = parent;
}
}
//-------------------------------SearchTree------------------------------------
struct Node * SearchTree(struct AVLtree * tree, int data) {
struct Node * p = tree->top.parent;
while(p != NULL) {
if(p->data == data) {
break;
} else if(data < p->data) {
if(p->left == NULL) break;
p = p->left;
} else {
if(p->right == NULL) break;
p = p->right;
}
}
// 如果未找到节点就返回,节点应该插入位置的父节点
return p;
}
//-------------------------------Insert------------------------------------
struct Node * Insert(struct AVLtree * tree, int data) {
struct Node * p = SearchTree(tree, data);
if(p != NULL && p->data == data) return p; // 不允许重复
struct Node * pNode = (struct Node *)malloc(sizeof(struct Node));
pNode->data = data;
pNode->balance = 0;
pNode->left = NULL;
pNode->right = NULL;
if(tree->top.parent == NULL) { // 当根节点为空时插入节点作为根节点
pNode->parent = NULL;
tree->top.parent = pNode;
}else {
// p 为插入节点 pNode 的父节点,根据数据大小判断是父节点的左子节点还是右子节点
pNode->parent = p;
if(data < p->data) {
p->left = pNode;
} else {
p->right = pNode;
}
BalanceInsert(tree, pNode);
}
TRACE(tree,"Insert complete");
return pNode;
}
void EraseNode(struct AVLtree * tree, struct Node * p);
//-------------------------------Erase------------------------------------
void Erase(struct AVLtree * tree, int data) {
if(tree->top.parent == NULL) return;
struct Node * p = SearchTree(tree, data);
if( p->data != data) return; // 树中不存在要删除的节点
EraseNode(tree, p);
TRACE(tree, "Erase complete");
}
void EraseNode(struct AVLtree * tree, struct Node * p) {
struct Node * parent = p->parent;
if(p->left == NULL && p->right == NULL) { // 删除节点无子树
if(p == tree->top.parent) {
tree->top.parent = NULL;
free(p);
return;
} else if(parent->left == p) {
parent->left = NULL;
parent->balance -= 1;
} else if(parent->right == p) {
parent->right = NULL;
parent->balance += 1;
}
if(parent->balance == 0) {
BalanceErase(tree, parent);
} else if(parent->balance == 2) {
if(RotateRight(tree, parent) == -1)
BalanceErase(tree, parent->parent);
} else if(parent->balance == -2) {
if(RotateLeft(tree, parent) == -1)
BalanceErase(tree, parent->parent);
}
free(p);
} else if(p->right == NULL && p->left != NULL) { // 当插入节点的右子树为空时,直接将左子树与父节点链接
if(p == tree->top.parent) {
tree->top.parent = p->left;
p->left->parent = NULL;
} else {
if(p == parent->left){
parent->left = p->left;
} else {
parent->right = p->left;
}
p->left->parent = parent;
BalanceErase(tree, p->left);
}
free(p);
} else if(p->right != NULL && p->left == NULL){ // 当插入节点的左子树为空时,直接将右子树与父节点链接
if(p == tree->top.parent) {
tree->top.parent = p->right;
p->right->parent = NULL;
} else {
if(p == parent->left){
parent->left = p->right;
} else {
parent->right = p->right;
}
p->right->parent = parent;
BalanceErase(tree, p->right);
}
free(p);
} else {
// 当左右子树都存在时,将删除的元素值替换为右子树的最小元素,从而转化为删除右子树的最小元素
struct Node * pos = p->right;
while(pos->left != NULL) pos = pos->left; // 找出右子树的最小元素
p->data = pos->data;
EraseNode(tree, pos);
}
}
//-------------------------------Find------------------------------------
struct Node * find(struct AVLtree * tree, int data) {
struct Node * p = tree->top.parent;
while(p != NULL) {
if(p->data == data) {
return p;
} else if(data < p->data) {
p = p->left;
} else {
p = p->right;
}
}
// 如果没找到就返回 NULL
return p;
}
//-------------------------------Print------------------------------------
void PrintAVLNode(struct Node * node) {
if(node == NULL) return;
PrintAVLNode(node->left); // <<2>>
printf("node: %d\n",node->data); // <<1>>
PrintAVLNode(node->right); // <<3>>
// 将上面调整为 1,2,3 循序就为先序序遍历,
// 调整为 2,1,3 循序就为中序遍历,
// 调整为 2,3,1 就为后序遍历
}
void PrintAVLtree(struct AVLtree * tree) {
PrintAVLNode(tree->top.parent);
}
void PrintByLevel(struct AVLtree * tree) {
if(tree->top.parent == NULL) return;
struct Queue queue;
struct Node * node;
int prePos = 0;
int preDistanceToTop = -1;
UpdateDeep(tree);
printf("xxxxxxxxxxxxxxxxxx Begin\n");
InitQueue(&queue);
PushBack(&queue, tree->top.parent);
while(!IsEmpty(&queue)) {
node = PopFront(&queue);
if(node->left != NULL) PushBack(&queue, node->left);
if(node->right != NULL) PushBack(&queue, node->right);
int level = tree->top.parent->deep-node->distanceToTop;
if(preDistanceToTop != node->distanceToTop) {
printf("\n");
for(int i=0; i<pow(2, level)-1; i++)
printf("%3s", "");
prePos = pow(2, node->distanceToTop-1)-1;
for(int i=0; i<pow(2, level+1)*(node->posAtTree-prePos-1); i++)
printf("%3s", "");
} else {
for(int i=0; i<pow(2, level+1)*(node->posAtTree-prePos)-1; i++)
printf("%3s", "");
}
preDistanceToTop = node->distanceToTop;
prePos = node->posAtTree;
printf("%3d", node->data);
// printf("%3d*%d", node->data, node->posAtTree);
}
DestroyQueue(&queue);
printf("\n");
printf("xxxxxxxxxxxxxxxxxx End\n");
}
//-------------------------------测试单元------------------------------------
void GetDeep(struct AVLtree * tree, struct Node * node) {
if(node == NULL) return;
if (node->left != NULL){
node->left->posAtTree = 2 * node->posAtTree;
node->left->distanceToTop = node->distanceToTop + 1;
}
if (node->right != NULL) {
node->right->posAtTree = 2 * node->posAtTree + 1;
node->right->distanceToTop = node->distanceToTop + 1;
}
GetDeep(tree, node->left);
GetDeep(tree, node->right);
if(node->left != NULL && node->right != NULL) {
node->deep = node->left->deep > node->right->deep ? node->left->deep : node->right->deep;
node->deep += 1;
if((fabs(node->left->deep - node->right->deep)>1)
|| (node->left->deep - node->right->deep != node->balance))
printf("Error: wrong balance: %d, should be: %d\n",
node->balance, node->left->deep - node->right->deep);
} else if (node->left != NULL){
node->deep = node->left->deep + 1;
if((node->left->deep != 1) || (node->balance != 1))
printf("Error: wrong balance with NULL right: %d, should be: %d\n",
node->balance, 1);
} else if (node->right != NULL) {
node->deep = node->right->deep + 1;
if((node->right->deep != 1) || (node->balance != -1))
printf("Error: wrong balance with NULL left: %d, should be: %d\n",
node->balance, -1);
} else {
node->deep = 1;
}
}
void UpdateDeep(struct AVLtree * tree) {
if(tree->top.parent == NULL) return;
tree->top.parent->posAtTree = 1;
tree->top.parent->distanceToTop = 1;
GetDeep(tree, tree->top.parent);
}
#include <time.h>
void Test() {
struct AVLtree tree;
srand((unsigned int)time(0));
for(int i = 0; i < 1000; i++) {
InitAVLtree(&tree);
for(int i = 0; i < rand() % 100; i++) {
for(int i = 0; i < rand() % 10; i++) {
Insert(&tree, rand() % 100);
}
for(int i = 0; i < rand() % 10; i++) {
Erase(&tree, rand() % 100);
}
}
UpdateDeep(&tree);
TRACE(&tree, "Test once again");
printf("xxxxxxxxxxxxxxxxxx %d\n", i);
getchar();
DestroyAVLtree(&tree);
}
}
int main(void)
{
struct AVLtree tree;
InitAVLtree(&tree);
Test();
// Print(&tree);
// struct Node * locate = find(&tree, 1);
// if(locate != NULL) printf("find node: %d\n", locate->data);
UpdateDeep(&tree);
g_traceStep = 0;
PrintByLevel(&tree);
DestroyAVLtree(&tree);
return 0;
}
Queue_h 文件
#include <stdio.h>
#include <stdlib.h>
typedef struct QueueNode {
void * data;
struct QueueNode * next;
}QueueNode;
typedef struct Queue {
struct QueueNode * first;
struct QueueNode * end;
}Queue;
void InitQueue(struct Queue * queue) {
queue->first = (struct QueueNode*)malloc(sizeof(struct QueueNode));
queue->first->next = NULL;
queue->end = queue->first;
}
void DestroyQueue(struct Queue * queue) {
if(queue->first != NULL) {
free(queue->first);
queue->first = NULL;
queue->end = NULL;
}
}
int IsEmpty(struct Queue * queue) {
return queue->first == queue->end;
}
void PushBack(struct Queue * queue, void * n) {
queue->end->data = n;
struct QueueNode * newNode = (struct QueueNode*)malloc(sizeof(struct QueueNode));
queue->end->next = newNode;
queue->end = newNode;
newNode->next = NULL;
}
void* PopFront(struct Queue * queue) {
void* result = queue->first->data;
queue->first = queue->first->next;
return result;
}