平衡二叉树
平衡二叉树的定义(AVL)
- 该二叉树为二叉搜索树,即每个节点的左孩子的值比该节点小,右孩子的值比该节点大。
- 该树每个节点的平衡因子的值的绝对值不超过1,节点的平衡因子定义为该节点左子树的高度减去该节点右子树的高度。
节点结构
1 typedef struct Node 2 { 3 int data; 4 int height; 5 6 struct Node *left; 7 struct Node *right; 8 struct Node *parent; 9 }NODE,*PNODE;
插入节点后的失衡和调整
最小失衡子树
在新插入的结点向上查找,以第一个平衡因子的绝对值超过 1 的结点为根的子树称为最小不平衡子树。也就是说,一棵失衡的树,是有可能有多棵子树同时失衡的。而这个时候,我们只要调整最小的不平衡子树,就能够将不平衡的树调整为平衡的树。
获得每个节点高度的代码:
1 int update_height(PNODE node) 2 { 3 if(node == NULL) 4 { 5 return 0; 6 } 7 else 8 { 9 int height_left = update_height(node->left); 10 int height_right = update_height(node->right); 11 node->height = (height_left >= height_right ? height_left : height_right) + 1; 12 return node->height; 13 } 14 }
获得某节点平衡因子的代码:
int get_factor(PNODE node) { if(node->left != NULL&&node->right != NULL) return node->left->height - node->right->height; else if(node->left != NULL) return node->left->height; else if(node->right != NULL) return -node->right->height; else return 0; }
寻找最小失衡子树的根节点代码:
1 PNODE get_first(PNODE node) 2 { 3 while(node != NULL&&get_factor(node) <= 1&&get_factor(node) >= -1) 4 { 5 node = node->parent; 6 } 7 return node; 8 }
调整策略1-左旋
(1)节点的右孩子替代此节点位置 (2)右孩子的左子树变为该节点的右子树 (3)节点本身变为右孩子的左子树
void L_rotate(PNODE node) { PNODE rson = NULL,parent = NULL; rson = node->right; parent = node->parent; node->right = rson->left; if(rson->left != NULL) { rson->left->parent = node; } rson->left = node; node->parent = rson; rson->parent = parent; if(parent != NULL) { if(parent->left == node) { parent->left = rson; } else { parent->right = rson; } } update_height(node); update_height(rson); }
调整策略2-右旋
(1)节点的左孩子代表此节点 (2)节点的左孩子的右子树变为节点的左子树 (3)将此节点作为左孩子节点的右子树。
1 void R_rotate(PNODE node) 2 { 3 PNODE lson = NULL,parent = NULL; 4 5 lson = node->left; 6 parent = node->parent; 7 8 node->left = lson->right; 9 if(lson->right != NULL) 10 { 11 lson->right->parent = node; 12 } 13 14 lson->right = node; 15 node->parent = lson; 16 17 lson->parent = parent; 18 if(parent != NULL) 19 { 20 if(parent->left == node) 21 { 22 parent->left = lson; 23 } 24 else 25 { 26 parent->right = lson; 27 } 28 } 29 30 update_height(node); 31 update_height(lson); 32 }
节点的几种插入情况
情况1
插入某节点的左孩子的左子树导致该节点失衡
策略
对该节点进行一次右旋即可
情况2
插入某节点的右孩子的右子树导致该节点失衡
策略
对该节点进行一次左旋即可
情况3
插入某节点的左孩子的右子树导致该节点失衡
策略
对该节点的左孩子进行一次左旋,然后对该节点经行一次右旋
情况4
插入某节点的右孩子的左子树导致该节点失衡
策略
对该节点的右孩子进行一次右旋,然后对该节点经行一次左旋
代码:
1 void balance(PNODE node) 2 { 3 PNODE p = get_first(node); 4 5 if(p == NULL) 6 { 7 return; 8 } 9 else 10 { 11 int factor = get_factor(p); 12 if(factor > 0) 13 { 14 factor = get_factor(p->left); 15 if(factor > 0)//在左孩子的左子树插入节点 16 { 17 R_rotate(p); 18 } 19 else//在左孩子的右子树插入节点 20 { 21 L_rotate(p->left); 22 R_rotate(p); 23 } 24 } 25 else 26 { 27 factor = get_factor(p->right); 28 if(factor < 0)//在右孩子的右子树插入节点 29 { 30 L_rotate(p); 31 } 32 else//在右孩子的左子树插入节点 33 { 34 R_rotate(p->right); 35 L_rotate(p); 36 } 37 } 38 } 39 }
完整代码(C)
#include<stdio.h> #include<stdlib.h> #include<malloc.h> #include<queue> #define SIZE 3 using namespace std; typedef struct Node { int data; int height; struct Node *left; struct Node *right; struct Node *parent; }NODE,*PNODE; //更新节点的高度 int update_height(PNODE node) { if(node == NULL) { return 0; } else { int height_left = update_height(node->left); int height_right = update_height(node->right); node->height = (height_left >= height_right ? height_left : height_right) + 1; return node->height; } } //获得节点的平衡因子 int get_factor(PNODE node) { if(node->left != NULL&&node->right != NULL) return node->left->height - node->right->height; else if(node->left != NULL) return node->left->height; else if(node->right != NULL) return -node->right->height; else return 0; } //右旋 void R_rotate(PNODE node) { PNODE lson = NULL,parent = NULL; lson = node->left; parent = node->parent; node->left = lson->right; if(lson->right != NULL) { lson->right->parent = node; } lson->right = node; node->parent = lson; lson->parent = parent; if(parent != NULL) { if(parent->left == node) { parent->left = lson; } else { parent->right = lson; } } update_height(node); update_height(lson); } //左旋 void L_rotate(PNODE node) { PNODE rson = NULL,parent = NULL; rson = node->right; parent = node->parent; node->right = rson->left; if(rson->left != NULL) { rson->left->parent = node; } rson->left = node; node->parent = rson; rson->parent = parent; if(parent != NULL) { if(parent->left == node) { parent->left = rson; } else { parent->right = rson; } } update_height(node); update_height(rson); } //获得距离插入节点最近的第一个非平衡节点 PNODE get_first(PNODE node) { while(node != NULL&&get_factor(node) <= 1&&get_factor(node) >= -1) { node = node->parent; } return node; } //插入节点并维持树的平衡 PNODE insert(PNODE *root,PNODE father,int key) { if(*root == NULL) { *root = (PNODE)malloc(sizeof(NODE)); (*root)->data = key; (*root)->left = NULL; (*root)->right = NULL; (*root)->parent = father; return *root; } else { if(key > (*root)->data) { insert(&(*root)->right,*root,key); } else if(key < (*root)->data) { insert(&(*root)->left,*root,key); } } } //插入节点后通过旋转调节二叉树 void balance(PNODE node) { PNODE p = get_first(node); if(p == NULL) { return; } else { int factor = get_factor(p); if(factor > 0) { factor = get_factor(p->left); if(factor > 0)//在左孩子的左子树插入节点 { R_rotate(p); } else//在左孩子的右子树插入节点 { L_rotate(p->left); R_rotate(p); } } else { factor = get_factor(p->right); if(factor < 0)//在右孩子的右子树插入节点 { L_rotate(p); } else//在右孩子的左子树插入节点 { R_rotate(p->right); L_rotate(p); } } } } //创建平衡二叉树 void create(PNODE *root,int datas[]) { *root = NULL; for(int i = 0;i < SIZE;i++) { PNODE p = insert(root,NULL,datas[i]); update_height(*root); balance(p); //更新根节点 while((*root)->parent != NULL) { *root = (*root)->parent; } } } //层序遍历平衡二叉树 void levelTraverse(PNODE pT) { queue<PNODE> que; que.push(pT); while(que.empty() == false) { printf("%d ",que.front()->data); if(que.front()->left != NULL) { que.push(que.front()->left); } if(que.front()->right != NULL) { que.push(que.front()->right); } que.pop(); } } int main() { int datas[3] = {1,2,3}; PNODE root; create(&root,datas); levelTraverse(root); return 0; }