| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3678 人关注过本帖
标题:大家讨论一下AVL 树插入的递归算法,觉得很难编写...
只看楼主 加入收藏
geninsf009
Rank: 3Rank: 3
等 级:论坛游民
威 望:8
帖 子:613
专家分:95
注 册:2008-8-16
结帖率:100%
收藏
 问题点数:0 回复次数:12 
大家讨论一下AVL 树插入的递归算法,觉得很难编写...
在下不才,这个算法差不多耗尽了我的所有的脑汁,下面是我写的非递归代码,觉得递归的确实太难写了...

////////////////////////////////////////////////////
//Insert()私有成员函数(非递归算法)
//在已经平衡的二叉树ptr中插入一个结点,并保持原有的平衡
//如果插入成功返回true,否则返回false
////////////////////////////////////////////////////
template<class T>
bool AVLTree<T>::Insert(T x,AVLNode<T>*& ptr)
{
    
    //首先不考虑平衡与否把结点插入到二叉树中去
    //并把从根到叶寻找插入位置经过的路径所有的结点保存入堆栈
                      
    //保存从插入位置到根结点的所有的结点的堆栈
    LinkedStack<AVLNode<T>* > Path;
    
    AVLNode<T>* pr;                //pr:p的父结点指针
    AVLNode<T>* p;                 //p:新插入的结点指针                  
    AVLNode<T>* q;                 //q:插入后平衡前pr的子树根结点

    //寻找插入的位置并把经过的结点保存入堆栈
    AVLNode<T>* cusor=ptr;         //游标指针从根结点开始
    
    while(cusor!=NULL)
    {
        if(x==cusor->data)         //如果要插入的结点已经存在
            return false;
        Path.Push(cusor);          //把经过的结点压入堆栈
        if(x>cusor->data)          //大于则从右子树继续往下
            cusor=cusor->right;
        else                       //小于则从左子树继续往下
            cusor=cusor->left;
    };
 
    //依据x的值新建结点p,并把p插入其中
    p=new AVLNode<T>(x);           //依据关键码x新建一个结点p
    if(ptr==NULL)                  //如果本来是空树
    {ptr=p;return true;}
    Path.getTop(pr);               //获取要插入结点p的父结点pr
    if(p->data<pr->data)           //如果小于父结点pr
        pr->left=p;                //则在左子树插入
    else                           //如果大于父结点pr
        pr->right=p;               //则在右子树插入

    //调整平衡因子,并对最小不平衡子树进行平衡化处理
    while(!Path.IsEmpty())         //循环条件:未到跟结点
    {
        //插入结点后调整相应结点的平衡因子
        Path.Pop(pr);              //从堆栈中取出一个根结点
        if(p==pr->left)            //如果新插入的p是pr的左子树
            pr->bf--;              //平衡因子减1
        else if(p==pr->right)      //如果新插入的p是pr的右子树
            pr->bf++;              //平衡因子加1

        //根据结点pr的平衡因子作相应的平衡化处理
        if(pr->bf==0)              //p是在pr的矮的子树上插入的
            break;                 //无需作平衡化处理
        else if(abs(pr->bf)==1)    //pr本身不需要平衡化处理,但影响其父结点
            p=pr;                  //回溯pr的父结点,子树p的高度已经加1了
        else                       //如果|pr->bf|==2,说明在高的那棵子树上插入了
        {
            if(pr->bf==2)          //如果pr是右子树高
            {
                q=pr->right;       //得到pr的右子树的根结点
                if(q->bf==1)       //如果右子树是右高,则pr属于RR型子树
                    RotateL(pr);   //对pr进行左单旋处理
                else               //如果右子树是左高,则pr属于RL型子树
                    RotateRL(pr);  //对pr进行先右后左双旋处理
            }
            else                   //如果pr是左子树高
            {
                q=pr->left;        //得到pr的左子树的根结点
                if(q->bf==1)       //如果左子树是右高则pr属于LR型子树
                    RotateLR(pr);  //对pr进行先左后右双旋处理
                else               //如果左子树是左高则pr属于型子树
                    RotateR(pr);   //对pr进行右单旋处理
            };
            break;                 //因为对子树pr进行平衡化处理后子树的高度不变
                                   //所以可以直接退出了而不要继续往上处理了
        };
    };

    //把平衡化后的子树和原来的树整体连接起来
    if(Path.IsEmpty())             //如果已经到树的根结点了
        ptr=pr;
    else                           //如果没有到根结点
    {
        Path.getTop(p);            //得到最小化不平衡子树平衡化后的父结点
        if(pr->data<p->data)
            p->left=pr;            //在左子树插入
        else
            p->right=pr;           //在右子树插入
    };
    
    return true;                   //插入成功
};
////////////////////////////////Insert()私有函数结束

还是觉得这个算法的非递归好理解一点,有哪位DX能详细解释一下递归的思想呢?
搜索更多相关主题的帖子: AVL 递归 算法 编写 
2008-10-06 16:04
很远的那颗星
Rank: 2
等 级:新手上路
威 望:4
帖 子:544
专家分:0
注 册:2008-6-30
收藏
得分:0 
geninsf009你真是大神啊,小生在此佩服一下先...代码是否经过测试了..
其实你能写出非递归,怎么会觉得递归难写呢?
给一个实现AVLTree的代码你看一下,包含递归实现AVLTree插入的.
#ifndef AVL_TREE_H
#define AVL_TREE_H

#include "dsexceptions.h"
#include <iostream>    // For NULL
using namespace std;

// AvlTree class
//
// CONSTRUCTION: with ITEM_NOT_FOUND object used to signal failed finds
//
// ******************PUBLIC OPERATIONS*********************
// void insert( x )       --> Insert x
// void remove( x )       --> Remove x (unimplemented)
// bool contains( x )     --> Return true if x is present
// Comparable findMin( )  --> Return smallest item
// Comparable findMax( )  --> Return largest item
// boolean isEmpty( )     --> Return true if empty; else false
// void makeEmpty( )      --> Remove all items
// void printTree( )      --> Print tree in sorted order
// ******************ERRORS********************************
// Throws UnderflowException as warranted

template <typename Comparable>
class AvlTree
{
  public:
    AvlTree( ) : root( NULL )
      { }
    AvlTree( const AvlTree & rhs ) : root( NULL )
    {
        *this = rhs;
    }

    ~AvlTree( )
    {
        makeEmpty( );
    }

    /**
     * Find the smallest item in the tree.
     * Throw UnderflowException if empty.
     */
    const Comparable & findMin( ) const
    {
        if( isEmpty( ) )
            throw UnderflowException( );
        return findMin( root )->element;
    }

    /**
     * Find the largest item in the tree.
     * Throw UnderflowException if empty.
     */
    const Comparable & findMax( ) const
    {
        if( isEmpty( ) )
            throw UnderflowException( );
        return findMax( root )->element;
    }

    /**
     * Returns true if x is found in the tree.
     */
    bool contains( const Comparable & x ) const
    {
        return contains( x, root );
    }

    /**
     * Test if the tree is logically empty.
     * Return true if empty, false otherwise.
     */
    bool isEmpty( ) const
    {
        return root == NULL;
    }

    /**
     * Print the tree contents in sorted order.
     */
    void printTree( ) const
    {
        if( isEmpty( ) )
            cout << "Empty tree" << endl;
        else
            printTree( root );
    }

    /**
     * Make the tree logically empty.
     */
    void makeEmpty( )
    {
        makeEmpty( root );
    }

    /**
     * Insert x into the tree; duplicates are ignored.
     */
    void insert( const Comparable & x )
    {
        insert( x, root );
    }
     
    /**
     * Remove x from the tree. Nothing is done if x is not found.
     */
    void remove( const Comparable & x )
    {
        cout << "Sorry, remove unimplemented; " << x <<
                " still present" << endl;
    }

    /**
     * Deep copy.
     */
    const AvlTree & operator=( const AvlTree & rhs )
    {
        if( this != &rhs )
        {
            makeEmpty( );
            root = clone( rhs.root );
        }
        return *this;
    }

  private:
    struct AvlNode
    {
        Comparable element;
        AvlNode   *left;
        AvlNode   *right;
        int       height;

        AvlNode( const Comparable & theElement, AvlNode *lt,
                                                AvlNode *rt, int h = 0 )
          : element( theElement ), left( lt ), right( rt ), height( h ) { }
    };

    AvlNode *root;


    /**
     * Internal method to insert into a subtree.
     * x is the item to insert.
     * t is the node that roots the subtree.
     * Set the new root of the subtree.
     */
    void insert( const Comparable & x, AvlNode * & t )
    {
        if( t == NULL )
            t = new AvlNode( x, NULL, NULL );
        else if( x < t->element )
        {
            insert( x, t->left );
            if( height( t->left ) - height( t->right ) == 2 )
                if( x < t->left->element )
                    rotateWithLeftChild( t );
                else
                    doubleWithLeftChild( t );
        }
        else if( t->element < x )
        {
            insert( x, t->right );
            if( height( t->right ) - height( t->left ) == 2 )
                if( t->right->element < x )
                    rotateWithRightChild( t );
                else
                    doubleWithRightChild( t );
        }
        t->height = max( height( t->left ), height( t->right ) ) + 1;
    }

    /**
     * Internal method to find the smallest item in a subtree t.
     * Return node containing the smallest item.
     */
    AvlNode * findMin( AvlNode *t ) const
    {
        if( t == NULL )
            return NULL;
        if( t->left == NULL )
            return t;
        return findMin( t->left );
    }

    /**
     * Internal method to find the largest item in a subtree t.
     * Return node containing the largest item.
     */
    AvlNode * findMax( AvlNode *t ) const
    {
        if( t != NULL )
            while( t->right != NULL )
                t = t->right;
        return t;
    }


    /**
     * Internal method to test if an item is in a subtree.
     * x is item to search for.
     * t is the node that roots the tree.
     */
    bool contains( const Comparable & x, AvlNode *t ) const
    {
        if( t == NULL )
            return false;
        else if( x < t->element )
            return contains( x, t->left );
        else if( t->element < x )
            return contains( x, t->right );
        else
            return true;    // Match
    }
/****** NONRECURSIVE VERSION*************************
    bool contains( const Comparable & x, AvlNode *t ) const
    {
        while( t != NULL )
            if( x < t->element )
                t = t->left;
            else if( t->element < x )
                t = t->right;
            else
                return true;    // Match

        return false;   // No match
    }
*****************************************************/

    /**
     * Internal method to make subtree empty.
     */
    void makeEmpty( AvlNode * & t )
    {
        if( t != NULL )
        {
            makeEmpty( t->left );
            makeEmpty( t->right );
            delete t;
        }
        t = NULL;
    }

    /**
     * Internal method to print a subtree rooted at t in sorted order.
     */
    void printTree( AvlNode *t ) const
    {
        if( t != NULL )
        {
            printTree( t->left );
            cout << t->element << endl;
            printTree( t->right );
        }
    }

    /**
     * Internal method to clone subtree.
     */
    AvlNode * clone( AvlNode *t ) const
    {
        if( t == NULL )
            return NULL;
        else
            return new AvlNode( t->element, clone( t->left ), clone( t->right ), t->height );
    }
        // Avl manipulations
    /**
     * Return the height of node t or -1 if NULL.
     */
    int height( AvlNode *t ) const
    {
        return t == NULL ? -1 : t->height;
    }

    int max( int lhs, int rhs ) const
    {
        return lhs > rhs ? lhs : rhs;
    }

    /**
     * Rotate binary tree node with left child.
     * For AVL trees, this is a single rotation for case 1.
     * Update heights, then set new root.
     */
    void rotateWithLeftChild( AvlNode * & k2 )
    {
        AvlNode *k1 = k2->left;
        k2->left = k1->right;
        k1->right = k2;
        k2->height = max( height( k2->left ), height( k2->right ) ) + 1;
        k1->height = max( height( k1->left ), k2->height ) + 1;
        k2 = k1;
    }

    /**
     * Rotate binary tree node with right child.
     * For AVL trees, this is a single rotation for case 4.
     * Update heights, then set new root.
     */
    void rotateWithRightChild( AvlNode * & k1 )
    {
        AvlNode *k2 = k1->right;
        k1->right = k2->left;
        k2->left = k1;
        k1->height = max( height( k1->left ), height( k1->right ) ) + 1;
        k2->height = max( height( k2->right ), k1->height ) + 1;
        k1 = k2;
    }

    /**
     * Double rotate binary tree node: first left child.
     * with its right child; then node k3 with new left child.
     * For AVL trees, this is a double rotation for case 2.
     * Update heights, then set new root.
     */
    void doubleWithLeftChild( AvlNode * & k3 )
    {
        rotateWithRightChild( k3->left );
        rotateWithLeftChild( k3 );
    }

    /**
     * Double rotate binary tree node: first right child.
     * with its left child; then node k1 with new right child.
     * For AVL trees, this is a double rotation for case 3.
     * Update heights, then set new root.
     */
    void doubleWithRightChild( AvlNode * & k1 )
    {
        rotateWithLeftChild( k1->right );
        rotateWithRightChild( k1 );
    }
};

#endif


是mark allen weiss写的,认识不?呵呵...

[[it] 本帖最后由 很远的那颗星 于 2008-10-6 22:08 编辑 [/it]]

Fighting~~~~~~~~
2008-10-06 22:07
geninsf009
Rank: 3Rank: 3
等 级:论坛游民
威 望:8
帖 子:613
专家分:95
注 册:2008-8-16
收藏
得分:0 
“很远的那颗星”兄,多谢指教啊:-)
代码已经通过测试了,考虑了整整一个星期,连吃饭都在想...
正在尝试着写递归算法呢,都快想得走火入魔了...

谢谢你的代码啊,weiss是大师,收下了,慢慢看.
2008-10-07 12:29
geninsf009
Rank: 3Rank: 3
等 级:论坛游民
威 望:8
帖 子:613
专家分:95
注 册:2008-8-16
收藏
得分:0 
这是我写的AVL树的实现,其中的Remove非算法已经编不下去了,

但其他的成员函数都已经通过测试了,这是在我感觉写了这么多的类中最难写的一个了,大家参考讨论:

#ifndef AVLTREE_H
#define AVLTREE_H

#include"LinkedStack.h"

////////////////////////////////////////////////////
//AVLNode结构 平衡二叉排序树的结点的定义
////////////////////////////////////////////////////
template<class T>
struct AVLNode
{
    AVLNode<T>* left;     //左子树
    AVLNode<T>* right;    //右子树
    T data;               //数据域
    //当前结点的平衡因子(即右子树高度减去左子树高度)
    //如果是平衡的二叉排序树的话bf应该为1,0,-1
    int bf;      
    //默认构造函数
    AVLNode():left(NULL),right(NULL),bf(0){};
    //带参数的构造函数
    AVLNode(T d,AVLNode<T>* l=NULL,AVLNode<T>* r=NULL)
    {data=d;left=l;right=r;bf=0;}
};
/////////////////////////////////////AVLNode结构结束

////////////////////////////////////////////////////
//AVLTree类模板  平衡二叉排序树树类的声明和定义
////////////////////////////////////////////////////
template<class T>
class AVLTree
{
protected:
    //AVLTree<T>的根结点
    AVLNode<T>* root;
    //在子树subTree中搜索关键码为x的结点的指针
    AVLNode<T>* Search(T x,AVLNode<T>*& subTree)const;
    //非递归:把关键码为x的结点插入到二叉排序树subTree中
    bool Insert(T x,AVLNode<T>*& subTree);
    //递归:把关键码插入到以subTree为根的子树中去
    bool InsertRev(T x,AVLNode<T>* subTree);
    //把关键码为x的结点在树中删除
    bool Remove(T x,AVLNode<T>*& subTree);
    //释放子树所有结点的内存
    void makeEmpty(AVLNode<T>* subTree);

    void RotateL(AVLNode<T>*& ptr);      //对结点ptr进行左单旋操作
    void RotateR(AVLNode<T>*& ptr);      //对结点ptr进行右单旋操作
    void RotateLR(AVLNode<T>*& ptr);     //对结点ptr先左后右单旋
    void RotateRL(AVLNode<T>*& ptr);     //对结点ptr先右后左单旋
    int Height(AVLNode<T>* ptr)const;    //求树的高度
    void DisplayAVL(AVLNode<T>* subTree);//递归:以广义表的形式显示该平衡二叉排序树

public:
    AVLTree(){root=NULL;};  //默认空构造函数
    AVLTree(int A[],int n); //带参数的构造函数
    ~AVLTree()              //析构函数,释放所有的结点的内存
    {makeEmpty(root);};
    Create(char* des);      //通过广义表描述字符串创建一个二叉搜索树
    bool Insert(T x)        //插入关键码为x的结点
    {return Insert(x,root);};
    bool Remove(T x)        //删除关键码为x的结点
    {return Remove(x,root);};
    AVLNode<T>* Search(T x) //寻找关键码为x的结点的指针
    {return Search(x,root);};
 
    //友员重载输出运算符<<
    friend ostream& operator<<(ostream& os,AVLTree<T>& R);
    //成员重载输入运算符>>
    friend istream& operator>>(istream& is,AVLTree<T>& R);

    int Height()const;     //得到树的高度
};
///////////////////////////////AVLTree类模板声明结束

////////////////////////////////////////////////////
//带参数的构造函数
//通过数组里的数的序列一次构造一棵AVL树
////////////////////////////////////////////////////
template<class T>
AVLTree<T>::AVLTree(int A[],int n)
{
    root=NULL;             //需要先把root根初始化为NULL
    for(int i=0;i<n;i++)
        Insert(A[i]);
};
////////////////////////////////带参数的构造函数结束

////////////////////////////////////////////////////
//Search()私有成员函数
//递归:在子树subTree中搜索具有关键码为x的指针结点
////////////////////////////////////////////////////
template<class T>
AVLNode<T>* AVLTree<T>::Search(T x,AVLNode<T>*& subTree)const
{
    if(subTree!=NULL)            //如果子树不空
    {
        if(subTree->data==x)
            return subTree;
        else if(x<subTree->data) //递归在左子树中寻找
            return Search(x,subTree->left);
        else                     //递归在右子树中寻找
            return Search(x,subTree->right);
    }
    else
        return NULL;
};
////////////////////////////////Search()私有函数结束

////////////////////////////////////////////////////
//makeEmpty()私有成员函数
//释放子树subTree所有结点的恶内存
////////////////////////////////////////////////////
template<class T>
void AVLTree<T>::makeEmpty(AVLNode<T>* subTree)
{
    //即采用后序方式释放内存
    if(subTree!=NULL)
    {
        //先递归释放左右子树的结点的内存
        makeEmpty(subTree->right);
        makeEmpty(subTree->left);
        //释放根结点的内存
        delete subTree;
    };
};
/////////////////////////////makeEmpty()私有函数结束

////////////////////////////////////////////////////
//RotateL()私有成员函数
//实现对以ptr为轴的结点进行左单旋,即把ptr右边的子
//结点"提拔"上来,而自己本身向左边下滑,即逆时针旋转
////////////////////////////////////////////////////
template<class T>
void AVLTree<T>::RotateL(AVLNode<T>*& ptr)
{
    AVLNode<T>* subL=ptr; //即将下放的结点指针
    ptr=ptr->right;       //将指针指向要旋转的结点
    subL->right=ptr->left;//把要旋转的结点的左子树置为subL结点的右子树
    ptr->left=subL;       //把subL置为要旋转的那个结点的左子树

    ptr->bf=0;            //ptr结点的平衡因子变为了0
    subL->bf=0;           //subL结点的平衡因子变为了0         
};
///////////////////////////////RotateL()私有函数结束

////////////////////////////////////////////////////
//RotateR()私有成员函数
//实现对以ptr为轴的结点进行右单旋,即把ptr左边的子
//结点"提拔"上来,而自己本身向右边下滑,即顺时针旋转
////////////////////////////////////////////////////
template<class T>
void AVLTree<T>::RotateR(AVLNode<T>*& ptr)
{
    AVLNode<T>* subR=ptr; //subR即将要被右旋
    ptr=ptr->left;        //ptr指向旋转的结点
    subR->left=ptr->right;//把ptr的右子树给subR结点的左子树
    ptr->right=subR;      //subR成为ptr的右子树

    ptr->bf=0;            //ptr,subR两个结点旋转后平衡因子为0
    subR->bf=0;
};
///////////////////////////////RotateR()私有函数结束

////////////////////////////////////////////////////
//RotateLR()私有成员函数
//对以ptr为根结点的子树进行先左后右旋转
////////////////////////////////////////////////////
template<class T>
void AVLTree<T>::RotateLR(AVLNode<T>*& ptr)
{
    AVLNode<T>* subR=ptr;       //要进行右旋的结点
    AVLNode<T>* subL=subR->left;//要进行左旋的结点
    ptr=subL->right;            //旋转轴结点

    //先对subL进行左旋
    subL->right=ptr->left;
    ptr->left=subL;
    if(ptr->bf<=0)              //如果是左子树高
        subL->bf=0;
    else                        //如果是右子树高
        subL->bf=-1;

    //再对subR进行右旋
    subR->left=ptr->right;
    ptr->right=subR;
    if(ptr->bf<=0)              //如果是左子树高
        subR->bf=1;
    else                        //如果是右子树高
        subL->bf=0;

    //对ptr平衡化结束
    ptr->bf=0;
};
//////////////////////////////RotateLR()私有函数结束

////////////////////////////////////////////////////
//RotateRL()私有成员函数
//对以ptr为根的子树进行先右后左的旋转
////////////////////////////////////////////////////
template<class T>
void AVLTree<T>::RotateRL(AVLNode<T>*& ptr)
{
    AVLNode<T>* subL=ptr;       //要进行左旋的结点指针
    AVLNode<T>* subR=ptr->right;//要进行右旋的结点指针
    ptr=subR->left;             //最底层失去平衡的结点

    //先进行右旋
    subR->left=ptr->right;        
    ptr->right=subR;
    if(ptr->bf>0)               //如果ptr是右子树高  
        subR->bf=0;             //subR结点的平衡因子就是0
    else                        //如果ptr是左子树高
        subR->bf=1;             //subL结点的平衡因子就是1

    //再进行左旋
    subL->right=ptr->left;      
    ptr->left=subL;
    if(ptr->bf==1)              //如果ptr是右子树高
        subL->bf=-1;
    else                        //如果ptr是左子树高
        subL->bf=0;

    //最后不平衡的结点得以平衡
    ptr->bf=0;
};
//////////////////////////////RotateRL()私有函数结束

////////////////////////////////////////////////////
//Insert()私有成员函数(非递归算法)
//在已经平衡的二叉树ptr中插入一个结点,并保持原有的平衡
//如果插入成功返回true,否则返回false
////////////////////////////////////////////////////
template<class T>
bool AVLTree<T>::Insert(T x,AVLNode<T>*& ptr)
{
    
    //首先不考虑平衡与否把结点插入到二叉树中去
    //并把从根到叶寻找插入位置经过的路径所有的结点保存入堆栈
                      
    //保存从插入位置到根结点的所有的结点的堆栈
    LinkedStack<AVLNode<T>* > Path;
    
    AVLNode<T>* pr;                //pr:p的父结点指针
    AVLNode<T>* p;                 //p:新插入的结点指针                  
    AVLNode<T>* q;                 //q:插入后平衡前pr的子树根结点

    //寻找插入的位置并把经过的结点保存入堆栈
    AVLNode<T>* cusor=ptr;         //游标指针从根结点开始
    
    while(cusor!=NULL)
    {
        if(x==cusor->data)         //如果要插入的结点已经存在
            return false;
        Path.Push(cusor);          //把经过的结点压入堆栈
        if(x>cusor->data)          //大于则从右子树继续往下
            cusor=cusor->right;
        else                       //小于则从左子树继续往下
            cusor=cusor->left;
    };
 
    //依据x的值新建结点p,并把p插入其中
    p=new AVLNode<T>(x);           //依据关键码x新建一个结点p
    if(ptr==NULL)                  //如果本来是空树
    {ptr=p;return true;}
    Path.getTop(pr);               //获取要插入结点p的父结点pr
    if(p->data<pr->data)           //如果小于父结点pr
        pr->left=p;                //则在左子树插入
    else                           //如果大于父结点pr
        pr->right=p;               //则在右子树插入

    //调整平衡因子,并对最小不平衡子树进行平衡化处理
    while(!Path.IsEmpty())         //循环条件:未到跟结点
    {
        //插入结点后调整相应结点的平衡因子
        Path.Pop(pr);              //从堆栈中取出一个根结点
        if(p==pr->left)            //如果新插入的p是pr的左子树
            pr->bf--;              //平衡因子减1
        else if(p==pr->right)      //如果新插入的p是pr的右子树
            pr->bf++;              //平衡因子加1

        //根据结点pr的平衡因子作相应的平衡化处理
        if(pr->bf==0)              //p是在pr的矮的子树上插入的
            break;                 //无需作平衡化处理
        else if(abs(pr->bf)==1)    //pr本身不需要平衡化处理,但影响其父结点
            p=pr;                  //回溯pr的父结点,子树p的高度已经加1了
        else                       //如果|pr->bf|==2,说明在高的那棵子树上插入了
        {
            if(pr->bf==2)          //如果pr是右子树高
            {
                q=pr->right;       //得到pr的右子树的根结点
                if(q->bf==1)       //如果右子树是右高,则pr属于RR型子树
                    RotateL(pr);   //对pr进行左单旋处理
                else               //如果右子树是左高,则pr属于RL型子树
                    RotateRL(pr);  //对pr进行先右后左双旋处理
            }
            else                   //如果pr是左子树高
            {
                q=pr->left;        //得到pr的左子树的根结点
                if(q->bf==1)       //如果左子树是右高则pr属于LR型子树
                    RotateLR(pr);  //对pr进行先左后右双旋处理
                else               //如果左子树是左高则pr属于型子树
                    RotateR(pr);   //对pr进行右单旋处理
            };
            break;                 //因为对子树pr进行平衡化处理后子树的高度不变
                                   //所以可以直接退出了而不要继续往上处理了
        };
    };

    //把平衡化后的子树和原来的树整体连接起来
    if(Path.IsEmpty())             //如果已经到树的根结点了
        ptr=pr;
    else                           //如果没有到根结点
    {
        Path.getTop(p);            //得到最小化不平衡子树平衡化后的父结点
        if(pr->data<p->data)
            p->left=pr;            //在左子树插入
        else
            p->right=pr;           //在右子树插入
    };
    
    return true;                   //插入成功
};
////////////////////////////////Insert()私有函数结束

////////////////////////////////////////////////////
//InsertRev()私有成员函数
//递归:插入具有制定关键码的结点
////////////////////////////////////////////////////
template<class T>
bool AVLTree<T>::InsertRev(T x,AVLNode<T>*& subTree)
{
    //如果子树为空
    if(subTree==NULL)
    {
        //依照关键码x新建一个结点
        AVLNode<T>* p=new AVLNode<T>(x);
        //直接把该结点挂上子树subTree
        subTree=p;
        //插入成功
        return true;
    };

    //如果在右子递归树插入
    if(x<subTree->data)
    {
        InsertRev(x,subbTree->left);

    }
    //如果在左子树递归插入
    else if(x>subTree->data)
    {
        InsertRev(x,subTree->right);
    }
    //如果等于说明插入失败
    else
        return false;
};
/////////////////////////////////InsertRev()函数结束

////////////////////////////////////////////////////
//Remove()私有成员函数
//非递归:删除已经平衡的AVL树中的具有指定关键码的结点
//注意:本代码还未编写成功,是在想不出来了
////////////////////////////////////////////////////
template<class T>
bool AVLTree<T>::Remove(T x,AVLNode<T>*& ptr)
{
    //首先在AVL树中找到要删除的那个结点
    LinkedStack<AVLNode<T>*> Stack;     //父结回溯用的堆栈
    AVLNode<T>* pr=ptr;                 //父结点指针
    AVLNode<T>* p;                      //要删除的结点的指针
    AVLNode<T>* q;                      //子树的根结点
    while(p!=NULL)
    {
        Stack.Push(p);                  //把经过的结点压入堆栈
        if(x<p->data)                   //如果在左子树删除
            p=p->left;
        else if(x>p->data)              //如果在右子树删除
            p=p->right;               
        else
            break;                      //如果已经找到
    };
    if(p==NULL)                         //说明没有找到要删除的结点
        return false;

    //采用非递归的方式把已经找到的结点删除并调整平衡因子
    while(!Stack.IsEmpty())             //从被删除的结点开始向上回溯
    {
        if(p->left==NULL                //如果左右子树都是空的
            && p->right==NULL)          //即删除的是叶子结点
        {
            Stack.Pop(pr);
            Stack.getTop(pr);           //从堆栈中获取p的父结点的指针pr
            if(pr->left==p)             //如果p是pr的左子树
            {
                pr->left==NULL;         //把pr的左指针域置空,删除结点p
                delete p;               //释放结点p的内存
                pr->bf++;               //原p的父结点pr的平衡因子加1
            }
            else if(pr->right==p)       //如果p是pr的右子树
            {
                pr->right==NULL;        //把pr的右指针域置空,删除结点p
                delete p;               //释放结点p的空间
                pr->bf--;               //原p的父结点pr的平衡因子减1
            }
        }
        else if(p->left!=NULL           //如果左右子女都存在
            && p->right!=NULL)
        {
            q=p;                        //以q为游标,从p开始
            while(q->left!=NULL)        //寻找p的右子树中序下的第一个结点
                q=q->left;
            p->data=q->data;            //把用结点q替代结点p的位置
            p=q;                        //问题转向删除结点q了
        }
    };
};
////////////////////////////////Remove()私有函数结束

////////////////////////////////////////////////////
//递归:Height()私有成员函数  得到树的高度
////////////////////////////////////////////////////
template<class T>  
int AVLTree<T>::Height(AVLNode<T>* subTree)const
{
    if(subTree==NULL)
        return 0;            //如果根结点为空,则树的高度为0
    else                     //如果树不空
    {
        int LH=Height(subTree->left); //递归得到左子树的高度
        int RH=Height(subTree->right);//递归得到右子树的高度
        if(LH>RH)
            return LH+1;              //如果左子树更高
        else
            return RH+1;              //如果右子树更高
    };
};
////////////////////////////////Height()私有函数结束

////////////////////////////////////////////////////
//Display()私有成员函数
//递归:以广义表的形式显示该平衡二叉排序树的内容
////////////////////////////////////////////////////
template<class T>
void AVLTree<T>::DisplayAVL(AVLNode<T>* subTree)
{
    if(subTree!=NULL)
    {
        //如果是叶子结点
        if(subTree->left==NULL && subTree->right==NULL)
            //直接显示而后面不用加括号
            cout<<subTree->data;
        //如果是子表
        else
        {
            cout<<subTree->data;
            //递归显示子树的内容
            cout<<"(";
            DisplayAVL(subTree->left);
            cout<<",";
            DisplayAVL(subTree->right);
            cout<<")";
        };
    };
};
///////////////////////////////Display()私有函数结束

////////////////////////////////////////////////////
//友元重载<<输出运算符 以广义表的形式显示树的内容
////////////////////////////////////////////////////
template<class T>
ostream& operator<<(ostream& os,AVLTree<T>& R)
{
    R.DisplayAVL(R.root);
    return os;
};
//////////////////////////////////////<<友元重载结束

////////////////////////////////////////////////////
//友元重载>>输入运算符
////////////////////////////////////////////////////
template<class T>
istream& operator>>(istream& is,AVLTree<T>& R)
{
    T x;               
    is>>x;             //键盘输入一个关键码
    R.Insert(x);       //把该关键码创建成结点插入其中
    return is;
};
//////////////////////////////////////>>友元重载结束

#endif
2008-10-07 12:34
很远的那颗星
Rank: 2
等 级:新手上路
威 望:4
帖 子:544
专家分:0
注 册:2008-6-30
收藏
得分:0 
geninsf兄啊,你可真是努力..呵呵.做事很细心啊,注释写得那么评细..
不过啊,你不觉得你注释写得太评细了吗? 就算是怕以后看代码时好看一点,容易理解一点,或是让别人能看懂,也不用这么详细的.这样得另外花你多少时间啊...拿你那
insert()说一下..比如说要将结点插入到哪里(左还是右),光写代码就够了,别人一看也能看得懂,(如果他事先看过书的话,如果别人没看过书,再详细也是没用的),光是这里就能省下一大堆注释了..我觉得只要在逻辑性比较强的地方注释一下就行了..

像weiss大师写的,虽然他的插入是递归的,效率上没你快,但它的代码基本不用注释,只需说明一下,别人一样能看懂..主要是它的结构清晰...函数模块分得细但合理..(虽然他这个代码是把什么都弄到一块了..不过他这样做可能是不想让我们随便复制,粘贴拿来用吧,我就是了 ),而且除了这个插入,再加那些旋转要一些注释外,其他的都基本不用写注释了..可以省下一点时间..
一家之言,呵呵...AVL我只是看了,没有自已写过,暑假时在红黑树与AVL之间,选择了写红黑树..不过...又忘得差不多了,而代码也在开学前的一次全盘大整理中 不小心格掉了,我的心血啊..

最后,我决定尝试写一下那remove函数,不过不知何年何月才写的出,最近在狂学OS中...

Fighting~~~~~~~~
2008-10-07 13:12
师妃暄
Rank: 6Rank: 6
等 级:贵宾
威 望:27
帖 子:805
专家分:107
注 册:2006-3-1
收藏
得分:0 
都是大神....额佩服

有实力才会有魅力 实力来自坚持不懈的努力
2008-10-07 15:23
geninsf009
Rank: 3Rank: 3
等 级:论坛游民
威 望:8
帖 子:613
专家分:95
注 册:2008-8-16
收藏
得分:0 
"星"兄说的是啊,我的注释多得有点迂腐了,有的时候觉得自己好不容易写出的
代码,不写那么多注释觉得自己有点过意不去,嘿嘿,数据结构确实博大精深,
大家共勉啊!
2008-10-07 18:12
很远的那颗星
Rank: 2
等 级:新手上路
威 望:4
帖 子:544
专家分:0
注 册:2008-6-30
收藏
得分:0 
哎,这次要让你失忘了...那删除节点算法真够晕的.以前看书,书上没给,还以为是想留给我们做练习..当时只是看了书上有的..没有去思考删除结点的算法,今天上午又看了一下AVL,试着写一下那remove...刚开始分析了一下可能出现的情况..就逻辑混乱了,菜鸟终是菜鸟..我那点分析就不帖了...贴一下csdn上某一神牛的解法...

AVL.rar (13.92 KB)

Fighting~~~~~~~~
2008-10-08 14:51
很远的那颗星
Rank: 2
等 级:新手上路
威 望:4
帖 子:544
专家分:0
注 册:2008-6-30
收藏
得分:0 
里面有他对自已删除结点代码的分析...一打开就能看到了...

没得比....路还很长啊...

Fighting~~~~~~~~
2008-10-08 14:53
geninsf009
Rank: 3Rank: 3
等 级:论坛游民
威 望:8
帖 子:613
专家分:95
注 册:2008-8-16
收藏
得分:0 
谢谢“星”兄啊,收下了,打算仔细去看看,Remove的算法今天我写了一个,可是结果不对,调试中呢,

头快大了,真佩服大师们,不仅实现了算法,而且代码的逻辑性,可读性都很好,我等差距甚远啊...
2008-10-08 20:16
快速回复:大家讨论一下AVL 树插入的递归算法,觉得很难编写...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.070511 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved