AVL树也是一种搜索二叉树(BST),即左孩纸比父节点小,右孩纸比父节点大。AVL树的插入就是通过遍历找到合适的位置插入,插入后可能会导致高度差大于1,所以需要通过旋转操作进行自平衡。AVL树的删除,找到删除节点,然后找到其子节点下最接近该节点val值的叶子节点,然后把该节点的val赋值为叶子节点的val,然后就转换成删除该节点下某一叶子节点了。最后进行自平衡调整。比如一个二叉树。
5
3 6
1 4 7
0 2
(5的左右节点3,6),3的左右节点是(1,4),1的左右节点是(0,2)
,准备删除3,找到3节点的位置,然后从3的孩纸节点中找到最接近他的叶子节点(2),然后把3节点的值改成2
5
2 6
1 4 7
0 2
然后题目就变成删除val为2的节点了。
花了半天时间学习AVL树,AVL树只要有LL,RR,LR,RL四种旋转操作,动态增加与减少都需要四种操作结合。AVL树比普通二叉树的结构体多了一个高度,用于保证左右子节点高度差小于2。在计算高度的时候,最好自己写一个函数,因为要判断是否为NULL,NULL则表示为0。如果用指针去取高度,为NULL的时候会报错。并且在计算高度差的时候,要注意是左节点减去右节点还是右节点减去左节点。
主要灵感来源于:http://blog.csdn.net/whucyl/article/details/17289841
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<vector> #include<queue> #include<algorithm> #include<cmath> using namespace std; struct Node { int val; int height; Node* left; Node* right; Node() { height = 1; left = NULL; right = NULL; } //更新高度 void UpdateHeight() { int leftheight = left ? left->height : 0; int rightheight = right ? right->height : 0; height = max(leftheight,rightheight)+1; } //左右子孩子高度差 int DisHeight() { int leftheight = left ? left->height : 0; int rightheight = right ? right->height : 0; return leftheight-rightheight; } }; Node* LL(Node* anode) { Node* bnode = anode->left; Node* cnode = bnode->right; bnode->right = anode; anode->left = cnode; //更新高度时,anode一定要先更新 anode->UpdateHeight(); bnode->UpdateHeight(); return bnode; } Node* RR(Node* anode) { Node* bnode = anode->right; Node* cnode = bnode->left; bnode->left = anode; anode->right = cnode; anode->UpdateHeight(); bnode->UpdateHeight(); return bnode; } Node* LR(Node* anode) { anode->left = RR(anode->left); return LL(anode); } Node* RL(Node* anode) { anode->right = LL(anode->right); return RR(anode); } Node* Insert(Node* node,int val) { if(node == NULL) { node = new Node(); node->val = val; } else if(val > node->val) { node->right = Insert(node->right,val); int disH = node->DisHeight(); if(disH == -2) { if(val > node->right->val) node = RR(node); else node = RL(node); } } else if(val < node->val) { node->left = Insert(node->left,val); int disH = node->DisHeight(); if(disH == 2) { if(val < node->left->val) node = LL(node); else node = LR(node); } } node->UpdateHeight(); return node; } Node* Delete(Node* node,int val) { if(node == NULL){return NULL;} else if(node->val < val) { node->right = Delete(node->right,val); } else if(node->val > val) { node->left = Delete(node->left,val); } else { if(node->left) { Node* nd; for(nd=node->left;nd->right != NULL;nd = nd->right); node->val = nd->val; node->left = Delete(node->left,nd->val); } else if(node->right) { Node* nd; for(nd=node->right;nd->left != NULL;nd = nd->left); node->val = nd->val; node->right = Delete(node->right,nd->val); } else { delete node; return NULL; } } if(node->DisHeight()==2) { if(node->left->DisHeight()==1) node = LL(node); else node = LR(node); } else if(node->DisHeight()==-2) { if(node->right->DisHeight()==-1) node = RR(node); else node = RL(node); } node->UpdateHeight(); return node; } void pre_travel(Node* node) { if(node==NULL) return; printf("%d ",node->val); pre_travel(node->left); pre_travel(node->right); } void in_travel(Node* node) { if(node==NULL) return; in_travel(node->left); printf("%d ",node->val); in_travel(node->right); } int main() { //test code Node *root = NULL; root = Insert(root,5); root = Insert(root,6); root = Insert(root,3); root = Insert(root,2); root = Insert(root,4); root = Insert(root,1); root = Insert(root,9); root = Insert(root,8); root = Insert(root,7); printf("先序遍历: "); pre_travel(root); printf(" "); printf("中序遍历: "); in_travel(root); printf(" "); root = Delete(root,6); root = Delete(root,1); printf(" 先序遍历: "); pre_travel(root); printf(" "); printf("中序遍历: "); in_travel(root); printf(" "); return 0; }
PAT1066,简单AVL的插入操作。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<vector> #include<algorithm> using namespace std; struct Node { int val; int H; Node* left; Node* right; Node() { H = 1; left = NULL; right = NULL; } int LH(){return left?left->H:0;} int RH(){return right?right->H:0;} void UpdateH(){H = max(LH(),RH())+1;} int DisH(){return LH() - RH();} }; Node* LL(Node* anode) { Node *bnode = anode->left; Node *cnode = bnode->right; bnode->right = anode; anode->left = cnode; anode->UpdateH(); bnode->UpdateH(); return bnode; } Node* RR(Node* anode) { Node *bnode = anode->right; Node *cnode = bnode->left; bnode->left = anode; anode->right = cnode; anode->UpdateH(); bnode->UpdateH(); return bnode; } Node* LR(Node* anode) { anode->left = RR(anode->left); return LL(anode); } Node* RL(Node* anode) { anode->right = LL(anode->right); return RR(anode); } Node* Insert(Node* node,int val) { if(node==NULL) { node = new Node(); node->val = val; } else if(val > node->val) { node->right = Insert(node->right,val); if(node->DisH()==-2) { if(val > node->right->val) node = RR(node); else node = RL(node); } } else if(val < node->val) { node->left = Insert(node->left,val); if(node->DisH()==2) { if(val < node->left->val) node = LL(node); else node = LR(node); } } node->UpdateH(); return node; } int main() { int n; scanf("%d",&n); Node* root = NULL; for(int i=0;i<n;++i) { int val; scanf("%d",&val); root = Insert(root,val); } printf("%d ",root->val); return 0; }
PAT1123,简单AVL的插入与已知广度遍历与宽度遍历的关系
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<vector> #include<algorithm> #include<queue> using namespace std; int n; struct Node { int val; int H; Node* left; Node* right; Node() { H = 1; left = NULL; right = NULL; } int LH(){return left?left->H:0;} int RH(){return right?right->H:0;} void UpdateH(){H = max(LH(),RH())+1;} int DisH(){return LH()-RH();} }; Node* LL(Node* anode) { Node* bnode = anode->left; Node* cnode = bnode->right; bnode->right = anode; anode->left = cnode; anode->UpdateH(); bnode->UpdateH(); return bnode; } Node* RR(Node* anode) { Node* bnode = anode->right; Node* cnode = bnode->left; bnode->left = anode; anode->right = cnode; anode->UpdateH(); bnode->UpdateH(); return bnode; } Node* LR(Node* anode) { anode->left = RR(anode->left); return LL(anode); } Node* RL(Node* anode) { anode->right = LL(anode->right); return RR(anode); } Node* Insert(Node* node,int val) { if(node==NULL) { node = new Node(); node->val = val; } else if(val < node->val) { node->left = Insert(node->left,val); if(node->DisH()==2) { if(val < node->left->val) node=LL(node); else node=LR(node); } } else if(val > node->val) { node->right = Insert(node->right,val); if(node->DisH()==-2) { if(val > node->right->val) node=RR(node); else node=RL(node); } } node->UpdateH(); return node; } vector<int> vi; void bfs(Node* node) { queue<Node*> qn; qn.push(node); bool bFirst = true; while(!qn.empty()) { Node* temp = qn.front(); qn.pop(); if(temp->left){qn.push(temp->left);} if(temp->right){qn.push(temp->right);} if(bFirst) bFirst = false; else printf(" "); printf("%d",temp->val); vi.push_back(temp->val); } printf(" "); } int Index = 0; int a[30],b[30]; void Travel(Node* node) { if(node == NULL) return; Travel(node->left); b[Index++] = node->val; Travel(node->right); } void Travel2(int k) { if(k >= n) return; Travel2(2*k+1); a[k] = b[Index++]; Travel2(2*k+2); } int main() { scanf("%d",&n); Node *root = NULL; for(int i=0;i<n;++i) { int val; scanf("%d",&val); root = Insert(root,val); } bfs(root); Travel(root); Index = 0; Travel2(0); bool bOK = true; for(int i=0;i<n;++i) if(a[i] != vi[i]){bOK = false;break;} if(bOK) printf("YES "); else printf("NO "); return 0; }
思考题:已知AVL数的插入顺序,求根节点值(有没有简单的方法)?