AVL树(二)
下面直接给出AVL树的实现代码,主要是基于前面的二叉查找树的基类实现方法的代码。
这里是直接修改原来的代码的,后面将会把它更新为继承的方式。
BinaryTreeNode.h 仅加入了一个balance平衡因子的数据成员和它的get,set方法
//此类为AVL查找树的树节点类 //定义的关键子,值,父节点和儿子节点 #ifndef BINARY_TREE_NODE_H #define BINARY_TREE_NODE_H #include "objectclass.h"//通用类 class BinaryTreeNode { private: ObjectClass *theKey;//关键字 ObjectClass *theValue;//值 BinaryTreeNode *parent;//父亲节点 BinaryTreeNode *left;//左儿子 BinaryTreeNode *right;//右儿子 //定义左右子树的宽度以便打印 int leftWidth; int rightWidth; //定义当前节点应该输出的位子,从左起点到右的宽度 int leftOutPutLen; //定义平衡因子 int balance; public: BinaryTreeNode(); BinaryTreeNode(ObjectClass *theKey,ObjectClass *theValue); ObjectClass *getKey(); ObjectClass *getValue(); BinaryTreeNode *getLeft(); BinaryTreeNode *getRight(); BinaryTreeNode *getParent(); int getLeftWidth(); int getRightWidth(); int getLeftOutPutLen(); int getBalance(); void setKey(ObjectClass *theKey); void setValue(ObjectClass *theValue); void setLeft(BinaryTreeNode *left); void setRight(BinaryTreeNode *Right); void setParent(BinaryTreeNode *parent); void setWidth(int,int);//设置子树宽度 void setLeftOutPutLen(int len); void setBalance(int balance); }; #endif
BinaryTreeNode.cpp 文件
#include "BinaryTreeNode.h" BinaryTreeNode::BinaryTreeNode() { theKey = NULL; theValue = NULL; parent = NULL; left = NULL; right = NULL; leftWidth=0; rightWidth=0; leftOutPutLen=0; balance=0; } BinaryTreeNode::BinaryTreeNode(ObjectClass *theKey,ObjectClass *theValue) { this->theKey = theKey; this->theValue = theValue; parent = NULL; left = NULL; right = NULL; leftWidth=0; rightWidth=0; leftOutPutLen=0; balance=0; } int BinaryTreeNode::getLeftWidth() { return leftWidth; } int BinaryTreeNode::getRightWidth() { return rightWidth; } ObjectClass *BinaryTreeNode::getKey() { return theKey; } ObjectClass *BinaryTreeNode::getValue() { return theValue; } BinaryTreeNode *BinaryTreeNode::getLeft() { return left; } BinaryTreeNode *BinaryTreeNode::getRight() { return right; } BinaryTreeNode *BinaryTreeNode::getParent() { return parent; } int BinaryTreeNode::getBalance() { return balance; } void BinaryTreeNode::setWidth(int leftWidth, int rightWidth) { this->leftWidth=leftWidth; this->rightWidth=rightWidth; } void BinaryTreeNode::setValue(ObjectClass *theValue) { this->theValue = theValue; } void BinaryTreeNode::setKey(ObjectClass *theKey) { this->theKey = theKey; } void BinaryTreeNode::setLeft(BinaryTreeNode *left) { this->left = left; } void BinaryTreeNode::setRight(BinaryTreeNode *right) { this->right = right; } void BinaryTreeNode::setParent(BinaryTreeNode *parent) { this->parent=parent; } int BinaryTreeNode::getLeftOutPutLen() { return leftOutPutLen; } void BinaryTreeNode::setLeftOutPutLen(int len) { this->leftOutPutLen = len; } void BinaryTreeNode::setBalance(int balance) { this->balance = balance; }
AVL.h 文件
//此类是AVL搜索树类的定义部分 #include "BinaryTreeNode.h" class BSTree { private: //根节点 BinaryTreeNode *root; public: BSTree(); public: BinaryTreeNode *get(ObjectClass *theKey);//搜索 BinaryTreeNode *getRoot();//返回根节点 BinaryTreeNode *remove(ObjectClass *theKey);//删除 void insert(ObjectClass *theKey, ObjectClass *theValue);//插入 void ascend(BinaryTreeNode *);//遍历 int calWidth(BinaryTreeNode *);//计算各节点的长度 void outPut();//输出 BinaryTreeNode *tree_minimum(BinaryTreeNode *p);//最小节点 BinaryTreeNode *tree_maximum(BinaryTreeNode *p);//最大节点 BinaryTreeNode *tree_successor(BinaryTreeNode *p);//后继节点 void leftRote(BinaryTreeNode *); void rightRote(BinaryTreeNode *); void deleteNode(BinaryTreeNode *); };
AVL.cpp文件
//此文件是AVL搜索树的实现部分 #include "AVL.h" #include <iostream> #include "queue.h" using namespace std; BSTree::BSTree() { root = NULL;//根节点默认为NULL } //查找关键字为theKey的节点并返回指向节点的指针,找不到则返回空指针 BinaryTreeNode *BSTree::get(ObjectClass *theKey) { BinaryTreeNode *p=root; while(p!=NULL) { //if(theKey < p->getKey()) if(theKey->Compare(p->getKey()) == -1) p=p->getLeft(); //if(theKey > p->getKey()) else if(theKey->Compare(p->getKey()) == 1) p=p->getRight(); else //如果找到了相同的关键字则成功返回 return p; } return NULL; } //插入一个节点,如果节点关键字已经存在则覆盖,否则插入到叶子节点处 void BSTree::insert(ObjectClass *theKey,ObjectClass *theValue) { BinaryTreeNode *firstBalanceNode=NULL; int Path=1;//记录firstBalanceNode开始往下的路径,以1开始为标记 //00010010表示左左右左 int k=0;//指示开始的位置,上例中k=4 BinaryTreeNode *p=root; //search pointer BinaryTreeNode *parent=NULL;//parent of p; while(p!=NULL) { if(p->getBalance() != 0) { firstBalanceNode = p; Path=1; k=0; } parent=p; //if(theKey < p->getKey()) if(theKey->Compare(p->getKey()) == -1) { k++; p=p->getLeft(); Path=(Path<<1);//如果是向左走则Path后面加个0 } //if(theKey > p->getKey()) else if(theKey->Compare(p->getKey()) == 1) { k++; p=p->getRight(); Path=(Path<<1); Path=Path+1;//如果是向右走,则Path后面加个1 } else { p->setValue(theValue); //如果找到相同的关键字则覆盖原有的 return; } } //等待插入的新节点 BinaryTreeNode *newNode = new BinaryTreeNode(theKey,theValue); if(root == NULL) root = newNode; else { //当p为空的时候parent最多只有一个儿子节点 //if(theKey < parent->getKey()) if(theKey->Compare(parent->getKey()) == -1) { parent->setLeft(newNode); newNode->setParent(parent); } else { parent->setRight(newNode); newNode->setParent(parent); } } //第一种情况是没有找到这种非平衡点 if(firstBalanceNode == NULL) { if(newNode == root) return; //自下而上一次更新平衡因子,直到根节点 while(newNode!=NULL) { if(newNode->getParent() == NULL) break; if(newNode == newNode->getParent()->getLeft()) newNode->getParent()->setBalance(newNode->getParent()->getBalance()+1); else newNode->getParent()->setBalance(newNode->getParent()->getBalance()-1); newNode = newNode -> getParent(); } return; } //第二种情况非平衡点刚好因为新点的加入而变为平衡点,这不会影响上面节点的因子, //与第一种情形可以合并写,不过为了看起来清晰就分开做 else if((firstBalanceNode->getBalance() == -1 && ((Path>>(k-1))&1)==0) || (firstBalanceNode->getBalance() == 1 && ((Path>>(k-1))&1)==1)) { //自下而上更新平衡因子,直到原来的非平衡点 while(newNode!=firstBalanceNode) { if(newNode->getParent() == NULL) break; if(newNode == newNode->getParent()->getLeft()) newNode->getParent()->setBalance(newNode->getParent()->getBalance()+1); else newNode->getParent()->setBalance(newNode->getParent()->getBalance()-1); newNode = newNode -> getParent(); } return; } //第三种情况,AVL树被破坏掉了,要通过旋转恢复 else { //首先依然是改变平衡因子 while(newNode!=firstBalanceNode) { if(newNode->getParent() == NULL) break; if(newNode == newNode->getParent()->getLeft()) newNode->getParent()->setBalance(newNode->getParent()->getBalance()+1); else newNode->getParent()->setBalance(newNode->getParent()->getBalance()-1); newNode = newNode -> getParent(); } if(((Path>>(k-1))&1)==0 && ((Path>>(k-2))&1)==0)//LL { firstBalanceNode->setBalance(0); firstBalanceNode->getLeft()->setBalance(0); rightRote(firstBalanceNode->getLeft());//右旋转 } else if(((Path>>(k-1))&1)==1 && ((Path>>(k-2))&1)==1)//RR { firstBalanceNode->setBalance(0); firstBalanceNode->getRight()->setBalance(0); leftRote(firstBalanceNode->getRight());//左旋转 } else if(((Path>>(k-1))&1)==0 && ((Path>>(k-2))&1)==1)//LR { int bal=firstBalanceNode->getLeft()->getRight()->getBalance(); firstBalanceNode->getLeft()->getRight()->setBalance(0); if(bal == 0) { firstBalanceNode->setBalance(0); firstBalanceNode->getLeft()->setBalance(0); } else if(bal == 1) { firstBalanceNode->setBalance(-1); firstBalanceNode->getLeft()->setBalance(0); } else { firstBalanceNode->setBalance(0); firstBalanceNode->getLeft()->setBalance(1); } leftRote(firstBalanceNode->getLeft()->getRight()); rightRote(firstBalanceNode->getLeft()); } else if(((Path>>(k-1))&1)==1 && ((Path>>(k-2))&1)==0)//RL { int bal=firstBalanceNode->getRight()->getLeft()->getBalance(); firstBalanceNode->getRight()->getLeft()->setBalance(0); if(bal == 0) { firstBalanceNode->setBalance(0); firstBalanceNode->getRight()->setBalance(0); } else if(bal == 1) { firstBalanceNode->setBalance(0); firstBalanceNode->getRight()->setBalance(-1); } else { firstBalanceNode->setBalance(1);//1 firstBalanceNode->getRight()->setBalance(0); } rightRote(firstBalanceNode->getRight()->getLeft()); leftRote(firstBalanceNode->getRight()); } } return; } //删除节点,如果这个节点含有少于两个儿子节点,则直接删除它,然后将它的儿子节点链接到它原来所在的位置 //如果这个节点含有两个儿子节点,则要先删除它的后继节点,然后将它的后继节点的值换给它 BinaryTreeNode *BSTree::remove(ObjectClass *theKey) { //先查找到要删除的节点指针 BinaryTreeNode *deletedNode=get(theKey); if(deletedNode==NULL) return NULL; //即将被删除的节点,注意这个节点最多只含有一个儿子节点 BinaryTreeNode *todelete; //被删除节点的儿子节点 BinaryTreeNode *nextNode; if(deletedNode->getLeft()==NULL || deletedNode->getRight()==NULL) //当要删除的节点只含有最多一个儿子节点时则即将被删除节点就是要删除的节点 todelete = deletedNode; else todelete = tree_successor(deletedNode);//否则的话删除它的后继节点 ////////////////////////////////////////////////////////////////////////////// //这一步是为了更新平衡因子调整树的结构而设计的 BinaryTreeNode *pend=todelete; while(pend!=NULL) { if(pend->getParent()==NULL)break;//根节点 if(pend == pend->getParent()->getLeft()) pend->getParent()->setBalance(pend->getParent()->getBalance()-1); else pend->getParent()->setBalance(pend->getParent()->getBalance()+1); pend=pend->getParent(); if(pend->getBalance() != 0)break; } ////////////////////////////////////////////////////////////////////////////// //获取唯一的儿子节点,准备当前即将删除节点的删除工作 if(todelete->getLeft()!=NULL) nextNode=todelete->getLeft(); else nextNode=todelete->getRight(); //开始删除节点 if(nextNode!=NULL) nextNode->setParent(todelete->getParent()); if(todelete->getParent()==NULL) root=nextNode; else if(todelete->getParent()->getLeft()==todelete) todelete->getParent()->setLeft(nextNode); else todelete->getParent()->setRight(nextNode); //节点成功删除,删完后在考虑将原来节点的后续节点值的替换 if(todelete!=deletedNode) { deletedNode->setKey(todelete->getKey()); deletedNode->setValue(todelete->getValue()); } //删除节点 delete todelete; //更新平衡因子 deleteNode(pend); //返回不平衡点 return pend; } //删除节点函数的辅助函数,用于更新平衡因子,调整树的结构,使之仍为AVL树 void BSTree::deleteNode(BinaryTreeNode *deletedNode) { if(deletedNode==NULL)return; if(deletedNode->getBalance()==1 || deletedNode->getBalance()==-1 //如果非平衡点删除之前的平衡因子是0,则无需调整 || deletedNode->getBalance()==0)return;//如果非平衡点是根节点且平衡因子是0则无需调整 if(deletedNode->getBalance()==2)//R { if(deletedNode->getLeft()->getBalance()==0)//R0 { deletedNode->setBalance(1); deletedNode->getLeft()->setBalance(-1); rightRote(deletedNode->getLeft()); return;// 经过R0旋转后,AVL树已经达到平衡所以直接返回即可 } else if(deletedNode->getLeft()->getBalance()==1)//R-1 { deletedNode->setBalance(0); deletedNode->getLeft()->setBalance(0); rightRote(deletedNode->getLeft()); } else//R1 { if(deletedNode->getLeft()->getRight()->getBalance()==0) { deletedNode->setBalance(0); deletedNode->getLeft()->setBalance(0); } else if(deletedNode->getLeft()->getRight()->getBalance()==1) { deletedNode->setBalance(-1); deletedNode->getLeft()->setBalance(0); } else { deletedNode->setBalance(0); deletedNode->getLeft()->setBalance(1); } deletedNode->getLeft()->getRight()->setBalance(0); leftRote(deletedNode->getLeft()->getRight()); rightRote(deletedNode->getLeft()); } } else if(deletedNode->getBalance()==-2)//L { if(deletedNode->getRight()->getBalance()==0)//L0 { deletedNode->setBalance(-1); deletedNode->getRight()->setBalance(1); leftRote(deletedNode->getRight()); return; } else if(deletedNode->getRight()->getBalance()==-1)//L-1 { deletedNode->setBalance(0); deletedNode->getRight()->setBalance(0); leftRote(deletedNode->getRight()); } else//L1 { if(deletedNode->getRight()->getLeft()->getBalance()==0) { deletedNode->setBalance(0); deletedNode->getRight()->setBalance(0); } else if(deletedNode->getRight()->getLeft()->getBalance()==-1) { deletedNode->setBalance(1); deletedNode->getRight()->setBalance(0); } else { deletedNode->setBalance(0); deletedNode->getRight()->setBalance(-1); } deletedNode->getRight()->getLeft()->setBalance(0); rightRote(deletedNode->getRight()->getLeft()); leftRote(deletedNode->getRight()); } } //如果不是0旋转则继续向根部寻找非平衡点, deletedNode=deletedNode->getParent();//首先从当前的被调整后的子树根节点开始出发 while(deletedNode!=NULL) { if(deletedNode->getParent()==NULL)break;//根节点 if(deletedNode == deletedNode->getParent()->getLeft()) deletedNode->getParent()->setBalance(deletedNode->getParent()->getBalance()-1); else deletedNode->getParent()->setBalance(deletedNode->getParent()->getBalance()+1); deletedNode=deletedNode->getParent(); if(deletedNode->getBalance() != 0)break;//找到非平衡点就退出,否则会一直找打根部 } deleteNode(deletedNode);//继续下一次更新 } //计算左右的宽度,使用递归算法 int BSTree::calWidth(BinaryTreeNode *p) { if(p!=NULL) { int leftWidth=0;//左宽度 int rightWidth=0;//右宽度 if(p->getLeft()!=NULL) leftWidth=calWidth(p->getLeft())+p->getKey()->getLength(); //左宽度是左子树的总宽度加上本节点的长度 if(p->getRight()!=NULL) rightWidth=calWidth(p->getRight())+p->getKey()->getLength(); //右宽度是右子树的总宽度加上本节点的长度 p->setWidth(leftWidth,rightWidth);//设置左右宽度 //返回本节点为根的子树总宽度 return leftWidth+rightWidth; } return 0; } //按照层次遍历子树并且打印出来 void BSTree::ascend(BinaryTreeNode *p) { if(p==NULL) return; calWidth(p);//计算左右子树的宽度 p->setLeftOutPutLen(p->getLeftWidth());//设置最顶层的左边预留宽度 //下面要用队列实现树的层次遍历 Queue<BinaryTreeNode *> Q; Q.EnQueue(p); int number=0;//存储下一层的元素个数 int numberLeave=1;//这一层还剩下多少元素 BinaryTreeNode *dep;//保存当前从队列弹出的节点指针 int preLeftWidth=0; //存储前一个节点的左宽度,以便后面一个节点的打印 //如果当前节点在最开始,则前一节点左宽度为0 bool firstIn=true; while(!Q.isEmpty())//打印所有节点 { dep=Q.DeQueue(); numberLeave--; if(dep!=NULL) { if(dep->getLeft()!=NULL) { Q.EnQueue(dep->getLeft());//左节点加入队列 number++;//下层节点加一 } if(dep->getRight()!=NULL) { Q.EnQueue(dep->getRight());//右节点加入队列 number++;//下层节点加一 } int leftOutPutLen=dep->getLeftWidth(); //如果是第一次进入就左边预留宽度就是当前节点自己的宽度 if(!firstIn) { if(dep==dep->getParent()->getLeft()) leftOutPutLen = dep->getParent()->getLeftOutPutLen()-dep->getRightWidth()-dep->getParent()->getKey()->getLength(); //如果当前节点是左儿子,则它的左预留宽度是父节点的预留宽度减去当前节点右宽度 else leftOutPutLen = dep->getParent()->getLeftOutPutLen()+dep->getLeftWidth()+dep->getParent()->getKey()->getLength(); //如果当前节点是右儿子,则它的左预留宽度是父节点的预留宽度加上当前节点的左宽度 dep->setLeftOutPutLen(leftOutPutLen);//设置预留宽度 } //根据当前节点左预留宽度和上一兄弟节点的结束宽度打印预留空格 for(int i=0;i<leftOutPutLen-preLeftWidth;i++) cout<<" "; dep->getKey()->OutPut();//打印当前节点 preLeftWidth=leftOutPutLen+dep->getKey()->getLength(); //计算当前节点的结束宽度,以便下一兄弟节点的打印 //如果当前节点在没有兄弟节点了就换行 if(numberLeave == 0) { cout<<endl; preLeftWidth=0; numberLeave = number; number = 0; } } firstIn=false; } } //输出,这里是默认从根节点输出,如果直接调用ascend则可以输出任何子树 void BSTree::outPut() { BinaryTreeNode *temp=root; ascend(temp); } BinaryTreeNode *BSTree::tree_minimum(BinaryTreeNode *p) { if(p==NULL) return NULL; BinaryTreeNode *pp=p; while(pp->getLeft()!=NULL) pp=pp->getLeft(); return pp; } BinaryTreeNode *BSTree::tree_maximum(BinaryTreeNode *p) { if(p==NULL) return NULL; BinaryTreeNode *pp=p; while(pp->getRight()!=NULL) pp=pp->getRight(); return pp; } //返回已知节点的后续节点 //如果这个节点有右子数,则返回右子树的最小节点 //否则向父节点寻找,找到第一个向右转的父节点为止 BinaryTreeNode *BSTree::tree_successor(BinaryTreeNode *p) { if(p==NULL) return NULL; BinaryTreeNode *pp=p; if(pp->getRight()!=NULL) return tree_minimum(pp->getRight()); BinaryTreeNode *y=p->getParent(); while(y!=NULL && pp==y->getRight()) { pp=y; y=y->getParent(); } return y; } BinaryTreeNode *BSTree::getRoot() { return root; } //左旋转,这里需要特别注意根节点的变化 void BSTree::leftRote(BinaryTreeNode *p) { BinaryTreeNode *parent=p->getParent(); if(parent==root) { root=p; p->setParent(NULL); } else { p->setParent(parent->getParent()); if(parent->getParent()->getLeft()==parent) parent->getParent()->setLeft(p); else parent->getParent()->setRight(p); } parent->setRight(p->getLeft()); if(p->getLeft()!=NULL) p->getLeft()->setParent(parent); p->setLeft(parent); parent->setParent(p); } //右旋转 void BSTree::rightRote(BinaryTreeNode *p) { BinaryTreeNode *parent=p->getParent(); if(parent==root) { root=p; p->setParent(NULL); } else { p->setParent(parent->getParent()); if(parent->getParent()->getLeft()==parent) parent->getParent()->setLeft(p); else parent->getParent()->setRight(p); } parent->setLeft(p->getRight()); if(p->getRight()!=NULL) p->getRight()->setParent(parent); p->setRight(parent); parent->setParent(p); }