代码改变世界

数据结构(C++)-AVL平衡二叉树

2009-04-10 17:54  Iron  阅读(1892)  评论(0编辑  收藏  举报

类定义文件

//AvlTree.h

#pragma once

//AvlTreeNode平衡二叉树节点

template <class T>

class AvlTreeNode

{

public:

       AvlTreeNode<T> *left;

       AvlTreeNode<T> *right;

       AvlTreeNode<T> *parent;

       int balanceFactor;//平衡因子

       T data;

       AvlTreeNode(const T& item, AvlTreeNode<T>* lptr=NULL, AvlTreeNode<T>* rptr=NULL, AvlTreeNode<T>* par=NULL, int balfac=0);

};

//AvlTree平衡二叉树

template <class T>

class AvlTree

{

public:

       AvlTreeNode<T>* root;

       AvlTreeNode<T>* current;

       int size;

       AvlTreeNode<T>* LL(AvlTreeNode<T>* tree);

       AvlTreeNode<T>* LR(AvlTreeNode<T>* tree);

       AvlTreeNode<T>* RR(AvlTreeNode<T>* tree);

       AvlTreeNode<T>* RL(AvlTreeNode<T>* tree);

       void buildParent(AvlTreeNode<T>* tree);

 

       bool RotateSubTree(AvlTreeNode<T>* tree);

       AvlTree(void);

       AvlTreeNode<T>* Search(const T item);

       bool Insert(T item);

       bool Delete(T item);

       void Destory(AvlTreeNode<T>* tree);

       ~AvlTree(void);

};

类实现文件

//AvlTree.cpp

#include "AvlTree.h"

template <class T>

AvlTreeNode<T>::AvlTreeNode(const T &item, AvlTreeNode<T> *lptr = NULL, AvlTreeNode<T> *rptr = NULL, AvlTreeNode<T>* pr=NULL, int balfac = 0):data(item),left(lptr),right(rptr),parent(pr),balanceFactor(balfac)

{ }

template <class T>

AvlTree<T>::AvlTree():root(NULL),size(0),current(NULL)

{ }

 

//向平衡二叉树中插入一个元素

template <class T>

bool AvlTree<T>::Insert(const T item)

{

       //先找到位置

       AvlTreeNode<T>* tempPosition = this->root;

       AvlTreeNode<T>* pre = tempPosition;

       for(;;)

       {

              //如果已经到达要插入的地方,则插入新节点

              if(tempPosition == NULL)

              {

                     //实例化新节点

                     AvlTreeNode<T>* newNode = new AvlTreeNode<T>(item);

                     //如果插入位置为其父节点的左节点,则把新节点挂接到其父节点的左节点上,否则挂接到其父节点的右节点上

                     if(tempPosition==this->root)

                     {

                            root = newNode;

                            size++;

                            return true;

                     }

                     else if(tempPosition == pre->left && item<pre->data)

                     {

                            newNode->parent = pre;

                            pre->left = tempPosition = newNode;

                            size++;

                            break;

                     }

                     else

                     {

                            newNode->parent = pre;

                            pre->right = tempPosition = newNode;

                            size++;

                            break;

                     }

              }

 

              else if(item < tempPosition->data)

              {

                     //保存tempPosition前一节点

                     pre = tempPosition;

                     //在左子数寻找插入点

                     tempPosition = tempPosition->left;

              }

              else if(item > tempPosition->data)

              {

                     //保存tempPosition前一节点

                     pre = tempPosition;

                     //在右子数寻找插入点

                     tempPosition = tempPosition->right;

              }

              else

              {

                     //已存在此元素

                     return false;

              }

       }

       //调整以使得树平衡

       int bf = 0;

       while(tempPosition->parent)

       {

              //bf表示平衡因子的改变量,当新节点插入到左子树,则平衡因子+1

              //当新节点插入到右子树,则平衡因子-1

              bf = item<tempPosition->parent->data?1:-1;

 

              tempPosition = tempPosition->parent;//将指针指向父节点

 

              tempPosition->balanceFactor += bf;//改变父节点的平衡因子

 

              bf = tempPosition->balanceFactor;//获取当前节点的平衡因子

              //判断当前节点平衡因子,如果为表示改子树已平衡,不需要在回溯

              //

              if(bf==0)

              {

                     return true;

              }

              else if(bf==2||bf==-2)

              {

                     //调整树以使其平衡

                     RotateSubTree(tempPosition);

                     buildParent(root);

                     root->parent = NULL;

                     return true;

              }

       }

       return true;

}

//寻找值为itemAvlTree节点

template <class T>

AvlTreeNode<T>* AvlTree<T>::Search(const T item)

{

       current = this->root;

       for(;;)

       {

              //currentNULL,没有此节点

              if(current==NULL)

                     return NULL;

              //current不为NULL,继续寻找

              if(item == current->data)

                     return current;

              else if(item < current->data)

                     current = current->left;

              else if(item > current->data)

                     current = current->right;

       }

}

 

//删除一个节点

template <class T>

bool AvlTree<T>::Delete(const T item)

{

       AvlTreeNode<T>* deleteNode = Search(item);

       //如果所删节点不存在,返回

       if(deleteNode==NULL)

              return false;

       //pre在以下的程序中是tempPosition的父节点

       AvlTreeNode<T>*  tempPosition = NULL;

       AvlTreeNode<T>* pre = tempPosition;

       //存储真正删除的节点

       AvlTreeNode<T>* trueDeleteNode;

       //当被删除结点存在左右子树时

       if (deleteNode->left != NULL && deleteNode->right != NULL)

       {

              //获取左子树

              tempPosition = deleteNode->left;

              //获取deleteNode的中序遍历前驱结点,并存放于tempPosition

              while (tempPosition->right != NULL)

              {  

                     //找到左子树中的最右下结点

                     tempPosition = tempPosition->right;

              }

              //用中序遍历前驱结点的值代替被删除结点的值

              deleteNode->data = tempPosition->data;

 

              if (tempPosition->parent == deleteNode)

              {

                     //如果被删元素的前驱是其左孩子

                     tempPosition->parent->left = tempPosition->left;

              }

              else

              {

                     tempPosition->parent->right = tempPosition->left;

              }

              //得到真正删除的节点

              trueDeleteNode = tempPosition;

       }

       else //当只有左子树或右子树或为叶子结点时

       {  

              //首先找到惟一的孩子结点

              pre = deleteNode->parent;

              tempPosition = deleteNode->left;

              if (tempPosition == NULL) //如果只有右孩子或没孩子

              {

                     tempPosition = deleteNode->right;

              }

 

              if (deleteNode!=root)

              {

                     //如果删除节点不是根节点

                     if (deleteNode->parent->left == deleteNode)

                     {   //如果被删结点是左孩子

                            deleteNode->parent->left = tempPosition;

                     }

                     else

                     {   //如果被删结点是右孩子

                            deleteNode->parent->right = tempPosition;

                     }

              }

              else 

              {

                     //当删除的是根结点时

                     root = tempPosition;

              }

              //得到真正删除的节点

              trueDeleteNode = deleteNode;

       }

       //pre为真正删除节点的父节点

       pre = trueDeleteNode==NULL?NULL:trueDeleteNode->parent;

       //删除完后进行旋转,现在pre指向实际被删除的结点

       while (pre)

       {   //bf表示平衡因子的改变量,当删除的是左子树中的结点时,平衡因子-1

              //当删除的是右子树的孩子时,平衡因子+1

              int bf = (trueDeleteNode->data <= pre->data) ? -1 : 1;

              pre->balanceFactor += bf; //改变当父结点的平衡因子

              tempPosition = pre;

              pre = pre->parent;

              bf = tempPosition->balanceFactor; //获取当前结点的平衡因子

              if (bf != 0) //如果bf==0,表明高度降低,继续后上回溯

              {

                     //如果bf为或-1则说明高度未变,停止回溯,如果为或-2,则进行旋转

                     //当旋转后高度不变,则停止回溯

                     if (bf == 1 || bf == -1 || !RotateSubTree(tempPosition))

                     {

                            break;

                     }

              }

       }

       buildParent(root);

       if(root!=NULL)

              root->parent = NULL;

       delete trueDeleteNode;//析构真正删除的节点

       size--;

       return true;

}

//调整函数

template <class T>

bool AvlTree<T>::RotateSubTree(AvlTreeNode<T>* tree)

{

       this->current = tree;

       bool tallChange = true;

       int bf = tree->balanceFactor;

       AvlTreeNode<T>* newRoot = NULL;

 

       if (bf == 2) //当平衡因子为时需要进行旋转操作

       {

              int leftBF = current->left->balanceFactor;//得到左子树的平衡因子

              if (leftBF == -1)

              {

                     newRoot = LR(tree);//LR型旋转(左子树中插入右孩子,先左后右双向旋转)

              }

              else if (leftBF == 1)

              {

                     newRoot = LL(tree); //LL型旋转(左子树中插入左孩子,右单转)

              }

              else //当旋转根左孩子的bf为时,只有删除时才会出现

              {

                     newRoot = LL(tree);

                     tallChange = false;

              }

       }

       if (bf == -2) //当平衡因子为-2时需要进行旋转操作

       {

              int rightBF = current->right->balanceFactor; //获取旋转根右孩子的平衡因子

              if (rightBF == 1)

              {

                     newRoot = RL(tree); //RL型旋转(右子树中插入左孩子,先右后左双向旋转)

              }

              else if (rightBF == -1)

              {

                     newRoot = RR(tree); //RR型旋转(右子树中插入右孩子,左单转)

              }

              else //当旋转根左孩子的bf为时,只有删除时才会出现

              {

                     newRoot = RR(tree);

                     tallChange = false;

              }

       }

       //更改新的子树根

       if (current->parent!=NULL)

       {

              //如果旋转根为不是AVL树的根

 

              //newRoot为新旋转后得到的当前子树的根,一下判断的作用是

              //如果原来的根是其父节点的左子树,则新根也挂接到其父节点的左子树,

              //否则挂接到右子树

              if (tree->data < (tree->parent)->data)

              {

                     current->parent->left = newRoot;

              }

              else

              {

                     current->parent->right = newRoot;

              }

       }

       else

       {

              //如果旋转根为AVL树的根,则指定新AVL树根结点

              this->root = newRoot;

       }

       return tallChange;

}

 

//LL型旋转,返回旋转后的新子树根

template <class T>

AvlTreeNode<T>* AvlTree<T>::LL(AvlTreeNode<T>* tree)

{

       AvlTreeNode<T>* treeNext = tree->left;

       tree->left = treeNext->right;

       treeNext->right = tree;

 

       if (treeNext->balanceFactor == 1)

       {

              tree->balanceFactor = 0;

              treeNext->balanceFactor = 0;

       }

       else //treeNext->balanceFactor==0的情况,删除时用

       {

              tree->balanceFactor = 1;

              treeNext->balanceFactor = -1;

       }

       return treeNext; //treeNext为新子树的根

}

//LR型旋转,返回旋转后的新子树根

template <class T>

AvlTreeNode<T>* AvlTree<T>::LR(AvlTreeNode<T>* tree)

{

       AvlTreeNode<T>* treeNext = tree->left;

       AvlTreeNode<T>* newRoot = treeNext->right;

       tree->left = newRoot->right;

       treeNext->right = newRoot->left;

       newRoot->left = treeNext;

       newRoot->right = tree;

 

       switch (newRoot->balanceFactor) //改变平衡因子

       {

       case 0:

              tree->balanceFactor = 0;

              treeNext->balanceFactor = 0;

              break;

       case 1:

              tree->balanceFactor = -1;

              treeNext->balanceFactor = 0;

              break;

       case -1:

              tree->balanceFactor = 0;

              treeNext->balanceFactor = 1;

              break;

       }

       newRoot->balanceFactor = 0;

       return newRoot; //newRoot为新子树的根

}

//RR型旋转,返回旋转后的新子树根

template <class T>

AvlTreeNode<T>* AvlTree<T>::RR(AvlTreeNode<T>* tree)

{

       AvlTreeNode<T>* treeNext = tree->right;

       tree->right = treeNext->left;

       treeNext->left = tree;

 

       if (treeNext->balanceFactor == -1)

       {

              tree->balanceFactor = 0;

              treeNext->balanceFactor = 0;

       }

       else //treeNext->balanceFactor==0的情况,删除时用

       {

              tree->balanceFactor = -1;

              treeNext->balanceFactor = 1;

       }

       return treeNext; //treeNext为新子树的根

}

//RL型旋转,返回旋转后的新子树根

template <class T>

AvlTreeNode<T>* AvlTree<T>::RL(AvlTreeNode<T>* tree)

{

       AvlTreeNode<T>* treeNext = tree->right;

       AvlTreeNode<T>* newRoot = treeNext->left;

       tree->right = newRoot->left;

       treeNext->left = newRoot->right;

       newRoot->right = treeNext;

       newRoot->left = tree;

 

       switch (newRoot->balanceFactor) //改变平衡因子

       {

       case 0:

              tree->balanceFactor = 0;

              treeNext->balanceFactor = 0;

              break;

       case 1:

              tree->balanceFactor = 0;

              treeNext->balanceFactor = -1;

              break;

       case -1:

              tree->balanceFactor = 1;

              treeNext->balanceFactor = 0;

              break;

       }

       newRoot->balanceFactor = 0;

       return newRoot; //newRoot为新子树的根

}

//重新建立所有节点的父节点连接

template <class T>

void AvlTree<T>::buildParent(AvlTreeNode<T>* tree)

{

       //如果树为空则直接返回,如果树有节点的parent置为当前tree节点

       if(tree==NULL)

       {

              return;

       }

       if(tree->left!=NULL)

       {

              tree->left->parent = tree;

       }

       if(tree->right!=NULL)

       {

              tree->right->parent = tree;

       }

       //递归遍历子节点建立父节点连接

       buildParent(tree->left);

       buildParent(tree->right);

}

//销毁平衡树

template <class T>

void AvlTree<T>::Destory(AvlTreeNode<T>* tree)

{

       //如果树为空

       if(tree==NULL)

              return;

       //如果树不为空

       if(tree->left!=NULL || tree->right!=NULL)

       {

              //析构左子树

              if(tree->left!=NULL)

              {

                     Destory(tree->left);

                     tree->left = NULL;

              }

              //析构右子树

              if(tree->right!=NULL)

              {

                     Destory(tree->right);

                     tree->right = NULL;

              }

       }

       //析构树

       delete tree;

}

 

template <class T>

AvlTree<T>::~AvlTree(void)

{

       Destory(root);

}

测试文件

//avlmain.cpp

//#include <vld.h>//测试内存泄漏工具

#include <iostream>

#include "AvlTree.cpp"

using namespace std;

//主函数测试

int main()

{

       AvlTree<int>* intAvlTree = new AvlTree<int>();

       intAvlTree->Insert(10);

       intAvlTree->Insert(14);

       intAvlTree->Insert(9);

       intAvlTree->Insert(13);

       intAvlTree->Insert(15);

       intAvlTree->Insert(12);

       intAvlTree->Insert(11);

 

       intAvlTree->Delete(13);

       intAvlTree->Delete(11);

       intAvlTree->Delete(14);

       intAvlTree->Delete(10);

       intAvlTree->Delete(9);

       intAvlTree->Delete(15);

       intAvlTree->Delete(12);

       //cout<<intAvlTree->Search(11)->data;

       delete intAvlTree;

       return 1;

}

最近在重新看数据结构,偶然看到AVL树,以前没有实现过,现在有空,就写了一个,希望大家批评指正。

参考资料:

1.http://www.cnblogs.com/abatei/archive/2008/11/17/1335031.html

这个资料里面的旋转讲的非常好,我的avl实现基本在此文章提供的代码上修改

2.《数据结构 基于c++模板类的实现》作者:余腊生

看懂avl的原理,此书的讲解功不可没