P3369 【模板】普通平衡树
生活随笔
收集整理的這篇文章主要介紹了
P3369 【模板】普通平衡树
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
P3369 【模板】普通平衡樹
題目描述
您需要寫一種數據結構(可參考題目標題),來維護一些數,其中需要提供以下操作:
輸入輸出格式
輸入格式:
?
第一行為nnn,表示操作的個數,下面nnn行每行有兩個數optoptopt和xxx,optoptopt表示操作的序號( 1≤opt≤6 1 \leq opt \leq 6 1≤opt≤6 )
?
輸出格式:
?
對于操作3,4,5,63,4,5,63,4,5,6每行輸出一個數,表示對應答案
?
輸入輸出樣例
輸入樣例#1: 復制
10 1 106465 4 1 1 317721 1 460929 1 644985 1 84185 1 89851 6 81968 1 492737 5 493598輸出樣例#1: 復制
106465 84185 492737說明
時空限制:1000ms,128M
1.n的數據范圍: n≤100000 n \leq 100000 n≤100000
2.每個數的數據范圍: [?107,107][-{10}^7, {10}^7][?107,107]
來源:Tyvj1728 原名:普通平衡樹
https://www.luogu.org/problemnew/show/P3369
https://www.cnblogs.com/ppprseter/p/9382132.html
自己在網上找了一個,但是沒有實現3 4 功能
#include <stdio.h> #include <stdlib.h> #include <iostream> using namespace std; typedef struct AVLNode *Tree; typedef int ElementType; struct AVLNode {int depth; //深度,這里計算每個結點的深度,通過深度的比較可得出是否平衡Tree parent; //該結點的父節點,方便操作ElementType val; //結點值Tree lchild;Tree rchild;AVLNode(int val=0) //默認構造函數{parent=NULL;depth=0;lchild=rchild=NULL;this->val=val;} }; Tree insert_val(Tree&,Tree,Tree); Tree remove(Tree&,ElementType); Tree remove_val(Tree &,Tree &); void update_depth(Tree); int get_balance(Tree); int is_balance(Tree); Tree *Find_Min(Tree&); Tree connect34(Tree&,Tree&,Tree&,Tree&,Tree&,Tree&,Tree&); Tree rotateAt(Tree&,Tree&); void setchild(Tree &,Tree &,Tree &);//向AVL樹中插入val //參數:根,插入數據value //返回:新根結點 Tree Insert(Tree &root,ElementType val) {Tree temp=NULL;Tree node=new AVLNode(val);//插入結點temp=insert_val(root,node,NULL); //調用真正的插入函數if (temp){update_depth(temp);root=rotateAt(root, temp);//檢查樹是否該調整}else //無需插入,釋放結點delete temp;return root; } //插入函數 //參數:根節點,待插結點,待插結點的父節點 //返回:插入結點 Tree insert_val(Tree &root,Tree node,Tree parent) {if (root==NULL){root=node;node->parent=parent; //設置當前結點的父結點return root; //返回插入結點}if (node->val<root->val) //插左子樹return insert_val(root->lchild, node,root);else if(node->val>root->val) //插右子樹return insert_val(root->rchild, node,root);else //已存在該結點,停止插入操作,返回NULLreturn NULL; } //3+4重構函數 //參數:見分析 //返回:新根 Tree connect34(Tree &a,Tree &b,Tree &c,Tree &T0,Tree &T1,Tree &T2,Tree &T3) {a->lchild=T0;if (T0)T0->parent=a;a->rchild=T1;if(T1)T1->parent=a;update_depth(a);c->lchild=T2;if(T2)T2->parent=c;c->rchild=T3;if(T3)T3->parent=c;update_depth(c);b->lchild=a;a->parent=b;b->rchild=c;c->parent=b;update_depth(b);return b; }Tree rotateAt(Tree &root,Tree &node) {Tree son,temp;Tree grandson;int balance=0; //平衡因子while (node!=NULL) //檢查其祖先是否需要調整,更新{update_depth(node); //更新當前結點的高度信息balance=is_balance(node); //獲取當前結點的平衡因子情況if (balance>1 || balance<-1) //平衡因子超標{if (balance>1) //左子樹高{if (is_balance(node->lchild)>0) //LL型{//找祖孫三代,后面的類似son=node->lchild; //找其左孩子grandson=son->lchild; //找其左孩子的左孩子son->parent=node->parent; //設置更新后的son的父節點temp=node;//重構node=connect34(grandson, son, node, grandson->lchild, grandson->rchild, son->rchild, node->rchild);setchild(son, temp, node);//設置son父節點的孩子為node}else //LR型{son=node->lchild;grandson=son->rchild;grandson->parent=node->parent;temp=node;node=connect34(son, grandson, node, son->lchild, grandson->lchild, grandson->rchild, node->rchild);setchild(grandson, temp, node); //設置grandson父節點的孩子為node}}else //右子樹高{if (is_balance(node->rchild)<0) //RR型{son=node->rchild;grandson=son->rchild;son->parent=node->parent;temp=node;node=connect34(node, son, grandson, node->lchild, son->lchild, grandson->lchild, grandson->rchild);setchild(son, temp, node); //設置son父節點的孩子為node}else //RL型{son=node->rchild;grandson=son->lchild;grandson->parent=node->parent;temp=node;node=connect34(node, grandson, son, node->lchild, grandson->lchild, grandson->rchild, son->rchild);setchild(grandson, temp, node); //設置grandson父節點的孩子為node}}if (node->parent==NULL) //到達根結點{root=node; //設置新的根結點break; //退出}}node=node->parent; //依次找到其父節點}return root; //返回新根 } void setchild(Tree &g,Tree &temp,Tree &node) {if (g->parent){if (g->parent->lchild==temp)g->parent->lchild=node;elseg->parent->rchild=node;} } //查找最小結點 Tree *Find_Min(Tree &root) {if (root->lchild){return Find_Min(root->lchild);}return &root; }//刪除操作 //參數:根,需要刪除的結點 //返回值: 返回刪除結點的父節點 Tree remove_val(Tree &root,Tree &node) {Tree parent=node->parent;Tree temp=NULL;//只有左孩子if (node->rchild==NULL && node->lchild!=NULL){temp=node;node=node->lchild; //指向左孩子node->parent=temp->parent;delete temp; //釋放結點update_depth(node); //更新當前結點信息}else if(node->lchild==NULL && node->rchild!=NULL) //只有右孩子{temp=node;node=node->rchild; //指向右結點node->parent=temp->parent;delete temp; //釋放結點update_depth(node); //更新當前結點信息}else if(node->rchild==NULL && node->lchild==NULL) //葉子結點{parent=node->parent; //找到其父節點if (parent) //如果父節點存在{delete node;node=NULL;update_depth(parent); //更新父節點高度信息}else //刪除的是根{delete root;root=NULL;}}else //既有左孩子也有右孩子,化繁為簡{Tree *tmp=Find_Min(node->rchild); //找到替代元素,temp為葉子結點node->val=(*tmp)->val; //更新值//判斷當前葉子結點是左孩子還是右孩子。parent=(*tmp)->parent;delete *tmp;*tmp=NULL;update_depth(parent);}return parent; }//找到刪除的結點,執行刪除操作,并根據情況調整AVL樹 //參數:根,需要刪除的val //返回:找到刪除結點的情況則返回新根,否則返回NULL Tree remove(Tree &root,ElementType val) {static Tree *temp=NULL;if (root==NULL){temp=NULL;return NULL;}else if(root->val<val) //在右子樹查找remove(root->rchild, val);else if(root->val>val) //在左子樹查找remove(root->lchild, val);else //找到了,標記一下temp=&root;if (temp){if (!root->parent) //如果已經返回到最后一次(也就是root是真正的樹根){Tree tmp=NULL;tmp=remove_val(root,*temp); //執行刪除操作return rotateAt(root, tmp);}return *temp;}return NULL; }//獲取當前結點的深度 int get_balance(Tree node) {if (node==NULL)return 0;return node->depth; } //返回當前平衡因子 int is_balance(Tree node) {if (node==NULL)return 0;elsereturn get_balance(node->lchild)-get_balance(node->rchild); }//更新當前深度 void update_depth(Tree node) {if (node==NULL)return;else{int depth_Lchild=get_balance(node->lchild); //左孩子深度int depth_Rchild=get_balance(node->rchild); //右孩子深度node->depth=max(depth_Lchild,depth_Rchild)+1;} } //前序 void PreOrder(Tree root) {if (root==NULL)return;printf("%d ",root->val);PreOrder(root->lchild);PreOrder(root->rchild); } //中序 void InOrder(Tree root) {if (root==NULL)return;InOrder(root->lchild);printf("%d ",root->val);InOrder(root->rchild); } Tree getrightmost(Tree heap)//這個函數是求左子樹中最右的節點的函數 {while (heap!=NULL)heap=heap->rchild;return heap->parent;} Tree getPrenode(Tree heap)//heap代表當前要找前驅節點的節點 {if(heap==NULL)//如果當前節點為空,返回空return heap;if(heap->lchild!=NULL)//如果當前節點左子樹不為空,那么該節點的后繼節點為左子樹中最右的節點return getrightmost(heap->lchild);//找到左子數樹中最右的節點,并返回else //如果程序到達這里,說明當前節點的左子數為空{Tree parent=heap->parent;while (parent!=NULL&&heap!=parent->rchild)//第一個條件就是判斷那種特殊情況的,一直延伸到當前節點沒有父親節點時,那么parent為空,這個條件不滿足,函數返回空{ //第二個條件是判斷當前節點是否為該父親節點的右孩子,如果不是,繼續執行下面的代碼,如果是,說明這個父親節點就是heap節點的前驅節點heap=parent;parent=heap->parent;}return parent;} } Tree getleftmost(Tree heap)//這個函數是求右子樹中最左的節點的函數 {while (heap!=NULL)heap=heap->lchild;return heap->parent; } Tree getsuccessornode(Tree heap)//heap代表當前要找后繼節點的節點 {if(heap==NULL)//如果當前節點為空,返回空return heap;if(heap->rchild!=NULL)//如果當前節點右子樹不為空,那么該節點的后繼節點為右子樹中最左的節點return getleftmost(heap->rchild);//找到右子數樹中最左的節點,并返回else //如果程序到達這里,說明當前節點的右子數為空{Tree parent=heap->parent;while (parent!=NULL&&heap!=parent->lchild)//第一個條件就是判斷那種特殊情況的,一直延伸到當前節點沒有父親節點時,那么parent為空,這個條件不滿足,函數返回空{ //第二個條件是判斷當前節點是否為該父親節點的左孩子,如果不是,繼續執行下面的代碼,如果是,說明這個父親節點就是heap節點的后繼節點heap=parent;parent=heap->parent;}return parent;} }Tree Find(Tree T,int x){while(T != NULL){if(T->val == x){return T;}elseif(x > T->val){T = T->rchild; }else{T = T->lchild; }}return T; } int last; void findMaxMin(int aim, Tree ptr){if(ptr!=NULL){findMaxMin(aim, ptr->lchild);if(last<aim && ptr->val>=aim) //找到小于aim的最大元素printf("a=%d\n",last);if(last<=aim && ptr->val>aim) //找到大于aim的最小元素printf("b=%d\n",ptr->val);last=ptr->val;findMaxMin(aim, ptr->rchild);}}int main() {Tree root=NULL;int n;cin>>n;cout<<"--------------"<<endl;for(int i=0;i<n;i++){int a,b;cin>>a>>b;switch(a){case 1:root = Insert(root, b);break;case 2:remove(root, b);break;case 5:findMaxMin(493598,root);Tree t=getPrenode(Find(root,b));if(t!=NULL) cout<<t->val<<endl;break; case 6:findMaxMin(81968,root);t=getsuccessornode(Find(root,b));if(t!=NULL) cout<<t->val<<endl;break; default:break;}}cout<<"--------------"<<endl; printf("前序:");PreOrder(root);printf("\n");printf("中序:");InOrder(root);printf("\n");return 0; }?
?
?
總結
以上是生活随笔為你收集整理的P3369 【模板】普通平衡树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一款自制的视频录制软件
- 下一篇: JS高级---函数中的this的指向,函