手把手教你写平衡二叉树
来源:互联网 发布:怎样找回以前淘宝店铺 编辑:程序博客网 时间:2024/06/16 10:07
因为上BST课的时候睡觉睡过了结果。。。,后者折腾了一个下午才写了出来,感谢http://blog.chinaunix.net/uid-24948645-id-3913917.html博客的详细解析,但是上面的不足之处在于代码是伪代码,基本实现不了,然后自己做了修改,改成c++的写法。
AVL树是最先发明的自平衡二叉查找算法,是平衡二叉树的一种。在AVL中任何节点的两个儿子子树的高度最大差别为1,所以它又被成为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来平衡这棵树。
假设把AVL树构造过程中需要重新平衡的节点叫做α。由于任意节点最多有两个儿子,因此高度不平衡时,α点的两颗子树的高度差2。这种不平衡可能出现在下面这四种情况:
1) 对α的左儿子的左子树进行一次插入(左旋)
其中D是新插入的节点,红色节点K2是失去平衡的节点。需要对K1和K2进行左旋调整即将K1作为根,将K2作为K1的左子树,K1的右子树调整为K2的左子树。如下图所示
进行左旋变换
node* L_Ratate(node *K2) //左旋{ node *K1; K1 = K2->Left; K2->Left = K1->Right; K1->Right = K2; //更新节点的高度 return K1;}
2)对α的右儿子的右子树进行一次插入(右旋)
将K2的右子树更改为K1的左子树,K1的左子树更改为K2即完成的右旋,如下图所示
进行右旋
node* R_Ratate(node* K2){ node* K1; K1 = K2->Right; K2->Right = K1->Left; K1->Left = K2; //更新节点高度 return K1;}
3)对α的右儿子的左子树进行一次插入(右左双旋)
右左双旋:先对K1和K2进行左旋,然后在对K2和K3进行右旋,最终实现平衡。如下图所示
进行一次左旋
进行一次右旋
node* DoubleL_Rotate(node* K3)//双向旋转(左右){ K3->Left = R_Ratate(K3->Left); return L_Ratate(K3);}
4)对α的左儿子的右子树进行一次插入(左右双旋)
左右双旋这里的左右指的是对α的左儿子的右子树进行插入时需要旋转。先对K1和K2进行右旋(跟第四种情况类似),然后再对K3和K2进行左旋,最终实现平衡。如下图所示
进行一次右旋
进行一次左旋
node* DoubleR_Rotate(node* K3)//双向旋转(右左){ K3->Right = L_Ratate(K3->Right); return R_Ratate(K3);}
完整代码:
#include<iostream>#include<algorithm>using namespace std;typedef struct Node{ int data; int bf;//用来表示平衡因子 struct Node *Left,*Right;} node;node* L_Ratate(node *K2) //左旋{ node *K1; K1 = K2->Left; K2->Left = K1->Right; K1->Right = K2; //更新节点的高度 return K1;}node* R_Ratate(node* K2){ node* K1; K1 = K2->Right; K2->Right = K1->Left; K1->Left = K2; //更新节点高度 return K1;}node* DoubleL_Rotate(node* K3)//双向旋转(左右){ K3->Left = R_Ratate(K3->Left); return L_Ratate(K3);}node* DoubleR_Rotate(node* K3)//双向旋转(右左){ K3->Right = L_Ratate(K3->Right); return R_Ratate(K3);}int Height(node* P){ if(P == NULL) return -1; //当构建根节点,或者是叶子节点的时候为-1+1正好为0 else return P->bf;}node* create_bst(node* bst,int x){ //cout<<"ok\n"; if(!bst) { //cout<<"ok\n"; bst=new node; bst->data=x; bst->bf=0; bst->Left=bst->Right=NULL; } else if(x<bst->data) { bst->Left=create_bst(bst->Left,x); if(Height(bst->Left)-Height(bst->Right)==2)//左子树插入节点所以高度是左子树高于右子树 { if(x<bst->Left->data)//对α的左儿子的左子树进行一次插入,需要左旋 bst=L_Ratate(bst); else//对α的左儿子的右子树进行一次插入,需要双旋 bst=DoubleL_Rotate(bst); } } else if(x>bst->data)//右子树插入新节点 { bst->Right = create_bst(bst->Right,x); if(Height(bst->Right) - Height(bst->Left)== 2)//因为是右子树插入新节点,所以高度是右子树高于左子树 { if(x > bst->Right->data)//对α的右儿子的右子树进行一次插入,需要右旋 bst = R_Ratate(bst); else//对α的右儿子的左子树进行一次插入,需要双旋 bst = DoubleR_Rotate(bst); } } bst->bf = max(Height(bst->Left), Height(bst->Right)) + 1; //cout<<"test="<<bst->bf<<endl; return bst;}void InOrder(node* bst){ if(!bst) return; else { InOrder(bst->Left); cout<<bst->data<<' '<<endl; InOrder(bst->Right); }}int main(){ int n; cout<<"请输入要构建的二叉平衡树序列长度"<<endl; cin>>n; cout<<"请输入要构建的二叉平衡树序列"<<endl; node *bst=NULL; for(int i=0; i<n; ++i) { int d; cin>>d; bst=create_bst(bst,d); } cout<<"....输出...."<<endl; InOrder(bst); return 0;}
- 手把手教你写平衡二叉树
- 手把手教你写平衡二叉树
- 手把手教你写二叉查找树Binary Search Tree(1)
- 自己动手写二叉平衡树
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写批处理
- 手把手教你写tar
- 手把手教你写设置
- 平衡二叉树你了解吗?
- Java框架--国际化
- androidstudio快捷键
- 如何修改发布系统的项目名
- RandomAccessFile 文件的插入和删除一行文字
- ((*strDest++=*strSrc++)!='\0'); 的理解
- 手把手教你写平衡二叉树
- Android app的activity如何被另一个app打开
- ffmpeg的源码编译方法
- android studio 使用第三方so方法及注意
- java 正则 持续更新中
- 对于HTTPServlet接口的理解
- 第十三节,Iterator和for...of循环
- 浏览器支持的html5事件 — 第13.4.7节
- 关于socket的套接字中输入输出流的理解