/*
(2) 前序、中序、后序遍历二叉树 (递归) 
(3) 前序、中序、后序遍历的非递归算法  
(4) 层次遍历二叉树  
(5) 在二叉树中查找给定关键字(函数返回值为成功1,失败0)  
(6) 交换各结点的左右子树  
(7) 求二叉树的深度  
(8) 叶子结点数 
(9) 删除某结点 
*/
        
#include<stdio.h>                       //引用头文件stdio.h 
#include<stdlib.h>                      //引用头文件stdlib.h 
#include<malloc.h>                      //引用头文件malloc.h 
        
#define MAXSIZE 100                     //用#define定义全局变量MAXSIZE的值为100 
#define OK      1                       //用#define定义全局变量OK的值为1 
#define ERROR   0                       //用#define定义全局变量ERROR的值为0 
        
typedef int Status;                     //定义Status为int类型来表示函数返回值状态 
typedef int ElemType;                   //定义ElemType为int类型来表示元素类型 
        
typedef struct BSTNode                  //定义平衡二叉树结构体 
{ 
    ElemType        data;               //结点存储的数据 
    int             height;             //结点的高度 
    struct BSTNode  *lchild,*rchild;    //左、右孩子指针 
}BSTNode,*BSTree; 
        
typedef BSTree Position;                //定义Position为BSTree来表示节点树中位置 
        
typedef struct                          //定义栈的结构体 
{ 
    BSTree          *base;              //在栈构造前和销毁后,base的值为NULL 
    BSTree          *top;               //栈顶指针 
    int             stacksize;          //当前已分配的存储空间,以元素为单位 
}Stack; 
        
typedef struct                          //定义队列的结构体 
{ 
    BSTree          *front;             //队头指针 
    BSTree          *rear;              //队尾指针 
    int             queuesize;          //当前已分配的存储空间,以元素为单位 
}Queue; 
        
Status InsertBST(BSTree &T,ElemType e); //实现树的节点的插入 
Status PreOrderTraverse(BSTree T);      //实现树的递归前序遍历 
Status InOrderTraverse(BSTree T);       //实现树的递归中序遍历 
Status PostOrderTraverse(BSTree T);     //实现树的递归后序遍历 
Status AllOrderTraverse(BSTree T);      //实现三种递归遍历的打印 
Status NonPreOrder(BSTree T,Stack S);   //实现树的非递归前序遍历 
Status NonInOder(BSTree T,Stack S);     //实现树的非递归中序遍历 
Status NonPostOrder(BSTree T,Stack S);  //实现树的非递归后序遍历 
Status NonAllOrder(BSTree T,Stack S);   //实现三种非递归遍历的打印 
Status LevelTraverse(BSTree T,Queue Q); //实现二叉树的层次遍历 
Status PostsSearch(BSTree T,ElemType e);//实现二叉树中给定关键字的查找 
Status SwapSubtree(BSTree T);           //实现结点左右子树的交换 
int    TreeDepth(BSTree T);             //实现二叉树深度的求值 
int    TotalNodeNum(BSTree T);          //实现二叉树总结点数的求值 
int    LeafNodeNum(BSTree T);           //实现二叉树叶子结点数的求值 
Status DeleteBST(BSTree &T,ElemType e); //实现树的节点的删除 
int    TreeHeight(BSTree T);            //实现树的高度的求值 
int    Max(int a,int b);                //实现两个数中求最大值 
Position MinElemSearch(BSTree T);       //实现最小元素的查找 
BSTree LeftRotate(BSTree g);            //实现二叉树一次右旋转操作 
BSTree RightRotate(BSTree g);           //实现二叉树一次左旋转操作 
BSTree L_RRotate(BSTree g);             //实现一次先左旋转再右旋转操作 
BSTree R_LRotate(BSTree g);             //实现一次先右旋转再左旋转操作 
Status CreatStack(Stack &S);            //实现栈的建立 
Status CreatQueue(Queue &Q);            //实现队列的建立 
        
Status InsertBST(BSTree &T,ElemType e)  //实现在二叉树中插入新结点的函数 
{ 
    if(T==NULL)                         //判断是否为空树,是则建建立一个根节点给树 
    { 
        T=(BSTree)malloc(sizeof(BSTNode)); 
        if(!T)                          //判断该节点是否建立失败 
        return ERROR; 
        T->data=e; 
        T->height=0;                    //根节点时,高度为0 
        T->lchild=T->rchild=NULL; 
    } 
    else if(e<T->data)                  //如果输入的元素比节点数据小,则向左插入 
    { 
        InsertBST(T->lchild,e);         //递归调用该函数本身 
        if(TreeHeight(T->lchild)-TreeHeight(T->rchild)==2) 
        {                               //判断二叉树是否出现不平衡状态,是则进入该分支 
            if(e<T->lchild->data)       //若输入的数据比左孩子结点的数据小,则进行右旋转 
            T=LeftRotate(T); 
            else                        //否则先进行左旋转再右旋转 
            T=L_RRotate(T); 
        } 
    } 
    else if(e>T->data)                  //如果输入的元素比节点数据大,则向右插入 
    { 
        InsertBST(T->rchild,e);         //递归调用该函数本身 
        if(TreeHeight(T->rchild)-TreeHeight(T->lchild)==2) 
        {                               //判断二叉树是否出现不平衡状态,是则进入该分支 
            if(e>T->rchild->data)       //若输入的数据比右孩子结点的数据大,则进行左旋转 
            T=RightRotate(T); 
            else                        //否则先进行右旋转再左旋转 
            T=R_LRotate(T); 
        } 
    }                                   //如果输入数据与节点数据相等,不需要进行操作 
    T->height=Max(TreeHeight(T->lchild),TreeHeight(T->rchild))+1; 
    return OK;                          //最后需要记录节点高度 
} 
        
Status PreOrderTraverse(BSTree T)       //实现递归前序遍历函数 
{ 
    if(T!=NULL)                         //判断是否为空树 
    { 
        printf("%d ",T->data); 
        PreOrderTraverse(T->lchild); 
        PreOrderTraverse(T->rchild); 
    } 
    return OK; 
} 
        
Status InOrderTraverse(BSTree T)        //实现递归中序遍历函数 
{ 
    if(T!=NULL)                         //判断是否为空树 
    { 
        InOrderTraverse(T->lchild); 
        printf("%d ",T->data); 
        InOrderTraverse(T->rchild); 
    } 
    return OK; 
} 
        
Status PostOrderTraverse(BSTree T)      //实现递归后序遍历函数 
{ 
    if(T!=NULL)                         //判断是否为空树 
    { 
        PostOrderTraverse(T->lchild); 
        PostOrderTraverse(T->rchild); 
        printf("%d ",T->data); 
    } 
    return OK; 
} 
        
Status AllOrderTraverse(BSTree T)       //实现各种递归遍历打印函数 
{ 
    printf("\n\t递归前序遍历如下:\n\t"); 
    PreOrderTraverse(T); 
    printf("\n"); 
    printf("\n\t递归中序遍历如下:\n\t"); 
    InOrderTraverse(T); 
    printf("\n"); 
    printf("\n\t递归后序遍历如下:\n\t"); 
    PostOrderTraverse(T); 
    printf("\n"); 
    return OK; 
} 
        
Status NonPreOrder(BSTree T,Stack S)    //实现非递归前序遍历函数 
{ 
    while(S.base!=S.top||T!=NULL)       //判断栈和树是否为空 
    { 
        while(T!=NULL)                  //向左子树一直循环到最左的节点 
        { 
            printf("%d ",T->data);      //输出元素 
            *S.top++=T; 
            T=T->lchild; 
        } 
        T=*--S.top;                     //实现出栈 
        T=T->rchild;                    //转向右子树 
    } 
    return OK; 
} 
        
Status NonInOder(BSTree T,Stack S)      //实现非递归中序遍历函数 
{ 
    while(S.base!=S.top||T!=NULL)       //判断栈和树是否为空 
    { 
        while(T!=NULL)                  //向左子树一直循环到最左的节点 
        { 
            *S.top++=T; 
            T=T->lchild; 
        } 
        T=*--S.top;                     //实现出栈 
        printf("%d ",T->data);          //输出元素 
        T = T->rchild;                  //转向右子树 
    } 
    return OK; 
} 
        
Status NonPostOrder(BSTree T,Stack S)   //实现非递归后序遍历函数 
{ 
    BSTree temp=NULL;                   //定义临时变量,用来标记刚刚访问过的节点 
    while(S.base!=S.top||T!= NULL)      //判断栈和树是否为空 
    { 
        while(T!=NULL)                  //向左子树一直循环到最左的节点 
        { 
            *S.top++=T; 
            T=T->lchild; 
        } 
        T=*(S.top-1);                   //取栈顶节点 
        if(T->rchild==NULL||T->rchild==temp) 
        {                               //如果该节点没有右孩子或者其右孩子刚刚被访问过 
            printf("%d ",T->data);      //输出元素 
            S.top--;                    //已访问,使其出栈 
            temp=T;                     //标记为刚刚访问过 
            T=NULL;                     //若遍历完以该节点为根的子树,且栈空,则结束,否则继续 
        } 
        else
        T=T->rchild;                    //转向右子树 
    } 
    return OK; 
} 
        
Status NonAllOrder(BSTree T,Stack S)    //实现各种非递归遍历打印函数 
{ 
    printf("\n\t非递归前序遍历如下:\n\t"); 
    CreatStack(S); 
    NonPreOrder(T,S); 
    printf("\n"); 
    printf("\n\t非递归中序遍历如下:\n\t"); 
    CreatStack(S); 
    NonInOder(T,S); 
    printf("\n"); 
    printf("\n\t非递归后序遍历如下:\n\t"); 
    CreatStack(S); 
    NonPostOrder(T,S); 
    printf("\n"); 
    return OK; 
} 
        
Status LevelTraverse(BSTree T,Queue Q)  //实现层次遍历函数 
{ 
    if(T!=NULL) 
    { 
        *Q.rear++=T; 
        while(Q.front!=Q.rear)          //判断队列是否为空 
        { 
            if(T->lchild!=NULL)         //判断左子树是否为空 
            *Q.rear++=T->lchild;        //左子树进队 
            if(T->rchild!=NULL)         //判断右子树是否为空 
            *Q.rear++=T->rchild;        //右子树进队 
            T=*Q.front++;               //实现出队操作 
            printf("%d ",T->data); 
            T=*Q.front;                 //此时的队头元素 
        } 
    } 
    return OK; 
} 
        
Status PostsSearch(BSTree T,ElemType e) //实现在二叉树中查找给定关键字函数 
{ 
    if(T!=NULL)                         //判断二叉树是否为空 
    { 
        if(e==T->data)                  //判断查找值是否与节点数据相等 
        return OK; 
        else if(e<T->data) 
        return PostsSearch(T->lchild,e);//查找值小于节点数据,则进入左子树查找 
        else
        return PostsSearch(T->rchild,e);//查找值大于节点数据,则进入右子树查找 
    } 
    else
    return ERROR; 
} 
        
Status SwapSubtree(BSTree T)            //实现交换各结点的左右子树函数 
{ 
    BSTree temp;                        //定义临时变量 
    if(T!=NULL)                         //判断二叉树是否为空 
    { 
        temp=T->lchild; 
        T->lchild=T->rchild; 
        T->rchild=temp; 
        SwapSubtree(T->lchild); 
        SwapSubtree(T->rchild); 
    } 
    return OK; 
} 
        
int TreeDepth(BSTree T)                 //实现求二叉树的深度函数 
{ 
    int deep,ldeep=0,rdeep=0; 
    if(T!=NULL)                         //判断二叉树是否为空 
    { 
        ldeep=TreeDepth(T->lchild); 
        rdeep=TreeDepth(T->rchild); 
        deep=Max(ldeep,rdeep)+1; 
    } 
    else return 0; 
    return deep; 
} 
        
int TotalNodeNum(BSTree T)              //实现统计总的结点数函数 
{ 
    int sum=0,lsum=0,rsum=0; 
    if(T!=NULL)                         //判断二叉树是否为空 
    { 
        lsum=TotalNodeNum(T->lchild); 
        rsum=TotalNodeNum(T->rchild); 
        sum=lsum+rsum+1; 
        return sum; 
    } 
    else return 0; 
} 
        
int LeafNodeNum(BSTree T)               //实现统计叶子结点数函数 
{ 
    int dot=0,ldot=0,rdot=0; 
    if(T!=NULL)                         //判断二叉树是否为空 
    { 
        if(T->lchild==NULL&&T->rchild==NULL)    //判断是否只含有一个节点 
        dot=1; 
        else
        { 
            ldot=LeafNodeNum(T->lchild); 
            rdot=LeafNodeNum(T->rchild); 
            dot=ldot+rdot; 
        } 
    } 
    else return 0; 
    return dot; 
} 
        
Status DeleteBST(BSTree &T,ElemType e)  //实现在二叉树中删除某结点的函数 
{ 
    Position temp;                      //定义临时变量 
    if(T==NULL)                         //判断二叉树是否为空 
    return ERROR; 
    else if(e<T->data)                  //需要删除的数据比节点数据小的情况 
    return DeleteBST(T->lchild,e);      //继续调用函数本身进入左子树查找 
    else if(e>T->data)                  //需要删除的数据比节点数据大的情况 
    return DeleteBST(T->rchild,e);      //继续调用函数本身进入右子树查找 
    else                                //即需要删除的数据与节点数据相等的情况 
    { 
        if(T->lchild!=NULL&&T->rchild!=NULL) 
        {                                   //左右孩子都存在的情况 
            temp=MinElemSearch(T->rchild);  //在右子树中找到最小的节点 
            T->data=temp->data;             //用找到的最小节点的数据代替要删除的节点的数据 
            DeleteBST(T->rchild,T->data);   //删除右子树刚刚找到的最小的节点 
        } 
        else                            //有一个孩子或者没有孩子的情况 
        { 
            temp=T; 
            if(T->lchild==NULL)         //判断是否没有孩子的情况 
            T=T->rchild; 
            else if(T->rchild==NULL)    //判断是否有一个孩子的情况 
            T=T->lchild; 
            free(temp); 
        } 
        return OK; 
    } 
} 
        
int TreeHeight(BSTree T)                //实现求树的高度的函数 
{ 
    if(T==NULL)                         //判断二叉树是否为空 
    return -1; 
    else
    return T->height; 
} 
        
int Max(int a,int b)                    //实现求较大值的函数 
{ 
    return a>b?a:b;                     //三元运算符,哪个值大返回哪个 
} 
        
Position MinElemSearch(BSTree T)        //实现查找最小元素的函数 
{ 
    if(T==NULL)                         //判断二叉树是否为空 
    return NULL; 
    else if(T->lchild==NULL)            //判断是否为没有子树的情况 
    return T; 
    else
    return MinElemSearch(T->lchild); 
} 
/*
	                             100                              85
                                 /  \               右旋         /    \
                               85   120         ------ ->       60    100  
                              /  \                                \   /   \
                            60    90                              80 90   120
                              \
                               80
*/       
BSTree LeftRotate(BSTree g)             //实现树的向右旋转函数 
{ 
    BSTree temp; 
    temp=g->lchild; 
    g->lchild=temp->rchild; 
    temp->rchild=g; 
    temp->height=Max(TreeHeight(temp->lchild),g->height)+1; 
    g->height=Max(TreeHeight(g->lchild),TreeHeight(g->rchild))+1; 
    return temp;                        //返回新的根节点 
} 
/*
                                  80                                   90  
                                 /  \             左旋               /    \
                               60    90          ---- ->            80    120
                                    /  \                           /  \   /
                                   85  120                        60  85 100
                                      /
                                    100     
*/        
BSTree RightRotate(BSTree g)            //实现树的向左旋转函数 
{ 
    BSTree temp; 
    temp=g->rchild; 
    g->rchild=temp->lchild; 
    temp->lchild=g; 
    g->height=Max(TreeHeight(g->lchild),TreeHeight(g->rchild))+1; 
    temp->height=Max(TreeHeight(g->rchild),g->height)+1; 
    return temp;                        //返回新的根节点 
} 
/*
	                          100                          100                        90
                             /  \         左旋            /  \       右旋           /    \
                            80  120     ------>          90  120    ------>        80   100  
                           / \                          /                         /  \     \
                          60 90                        80                        60  85    120
                            /                         / \
                           85                        60 85 
*/
BSTree L_RRotate(BSTree g)              //实现树的向左旋转再向右旋转函数 
{ 
    g->lchild=RightRotate(g->lchild);   //先左旋转 
    return LeftRotate(g);               //再右旋转 
} 
/*
                         80                               80                                   85  
                        /   \             右 旋          /  \               左 旋             /  \     
                       60   100          ------>        60   85            ------->          80 100
                            /  \                               \                            /   /  \       
                           85  120                             100                         60  90  120
                                  \                            /  \
                                  90                          90  120
*/     
BSTree R_LRotate(BSTree g)              //实现树的向右旋转再向左旋转函数 
{ 
    g->rchild=LeftRotate(g->rchild);    //先右旋转 
    return RightRotate(g);              //再左旋转 
} 
        
Status CreatStack(Stack &S)             //实现栈的建立函数 
{ 
    S.base=(BSTree*)malloc(MAXSIZE*sizeof(BSTree)); 
    if(!S.base)                         //判断是否建立失败 
    return ERROR; 
    S.top=S.base; 
    S.stacksize=MAXSIZE; 
    return OK; 
} 
        
Status CreatQueue(Queue &Q)             //实现队列的建立函数 
{ 
    Q.front=(BSTree*)malloc(MAXSIZE*sizeof(BSTree)); 
    if(!Q.front)                        //判断是否建立失败 
    return ERROR; 
    Q.rear=Q.front; 
    Q.queuesize=MAXSIZE; 
    return OK; 
} 
        
int main()                              //主函数 
{ 
    ElemType k,e,d; 
    int     i,n,ch; 
    char    c; 
    BSTree  T=NULL; 
    Stack   S; 
    Queue   Q; 
    printf("\n\t运行本程序需要先构造一个二叉树!\n"); 
    printf("\n\t请输入需要插入的元素个数:"); 
    scanf("%d",&n); 
    if(n==0) 
    { 
        printf("\n\t成功创建一个空二叉树!",n); 
        c=getchar();                    //用来吸收多余字符 
        c=getchar();                    //用来吸收多余字符 
    } 
    else
    { 
        printf("\n\t请输入要插入的%d个元素:",n); 
        for(i=0;i<n;i++)                //连续输入n个元素 
        { 
            scanf("%d",&e); 
            InsertBST(T,e);             //插入元素 
        } 
        printf("\n\t成功创建该二叉树!",n); 
        c=getchar();                    //用来吸收多余字符 
        c=getchar();                    //用来吸收多余字符 
    } 
        
    while(1)                            //进入程序的循环 
    { 
        system("cls");                  //实现清屏处理 
        printf("                        ☆ 实现平衡二叉树的各种算法 ☆                         \n"); 
        printf("                                                                               \n"); 
        printf(" ◆◆◆◆◆◆◆◆◆◆◆◆  请从下面的操作中选择一项  ◆◆◆◆◆◆◆◆◆◆◆◆◆\n"); 
        printf(" ◆                                                                          ◆\n"); 
        printf(" ◆                     ◆ 1.在二叉树中插入新结点                            ◆\n"); 
        printf(" ◆                     ◆ 2.实现递归的前序、中序、后序遍历二叉树            ◆\n"); 
        printf(" ◆                     ◆ 3.实现非递归的前序、中序、后序遍历二叉树          ◆\n"); 
        printf(" ◆                     ◆ 4.实现层次遍历二叉树                              ◆\n"); 
        printf(" ◆                     ◆ 5.在二叉树中查找给定关键字                        ◆\n"); 
        printf(" ◆                     ◆ 6.交换二叉树中各结点的左右子树                    ◆\n"); 
        printf(" ◆                     ◆ 7.实现二叉树的深度的求值                          ◆\n"); 
        printf(" ◆                     ◆ 8.统计二叉树中叶子结点数                          ◆\n"); 
        printf(" ◆                     ◆ 9.在二叉树中删除某结点                            ◆\n"); 
        printf(" ◆                     ◆ 0.退出本程序                                      ◆\n"); 
        printf(" ◆                                                                          ◆\n"); 
        printf(" ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆\n"); 
        printf("\n\t你的选择是:"); 
        scanf("%d",&ch); 
        switch(ch)                      //进入选择 
        { 
            case 1:                     //调用插入结点的函数 
            printf("\n\t请输入你想要插入的元素:"); 
            scanf("%d",&e); 
            if(InsertBST(T,e)==OK) 
            printf("\n\t成功插入元素%d!\n",e); 
            else
            printf("\n\t插入元素%d失败!\n",e); 
            break; 
            case 2:                     //调用打印各种递归遍历的函数 
            printf("\n\t平衡二叉树的各种递归遍历如下:\n"); 
            AllOrderTraverse(T); 
            break; 
            case 3:                     //调用打印各种非递归遍历的函数 
            printf("\n\t平衡二叉树的各种非递归遍历如下:\n"); 
            NonAllOrder(T,S); 
            break; 
            case 4:                     //调用打印层次遍历的函数 
            printf("\n\t平衡二叉树的层次遍历如下:\n\t"); 
            CreatQueue(Q);              //创建队列 
            LevelTraverse(T,Q); 
            printf("\n"); 
            break; 
            case 5:                     //调用关键字查找的函数 
            printf("\n\t请输入你想要查找的关键字:"); 
            scanf("%d",&k); 
            if(PostsSearch(T,k)==OK)    //返回查找的值,成功返回1,失败则返回0 
            printf("\n\t成功找到关键字%d!\n",k); 
            else
            printf("\n\t没有找到关键字%d!\n",k); 
            break; 
            case 6:                     //调用转换子树的函数 
            if(SwapSubtree(T)==OK) 
            printf("\n\t成功交换左右子树!\n"); 
            else
            printf("\n\t交换左右子树失败!\n"); 
            break; 
            case 7:                     //调用求二叉树深度的函数 
            printf("\n\t平衡二叉树的深度是:"); 
            printf("%d\n",TreeDepth(T)); 
            break; 
            case 8:                     //调用统计树结点数的函数 
            printf("\n\t平衡二叉树的总结点数是:"); 
            printf("%d\n",TotalNodeNum(T)); 
            printf("\n\t平衡二叉树的叶子结点数是:"); 
            printf("%d\n",LeafNodeNum(T)); 
            break; 
            case 9:                     //调用删除结点的函数 
            printf("\n\t请输入你想要删除的元素:"); 
            scanf("%d",&d); 
            if(DeleteBST(T,d)==OK) 
            printf("\n\t成功删除元素%d!\n",d); 
            else
            printf("\n\t删除失败,没有找到元素%d!\n",d); 
            break; 
            case 0:                     //输入0,则推出本程序 
            return 0; 
            break; 
            default:                    //如果输入非法字符,则进入该分支 
            c=getchar();                //用来吸收多余字符 
            printf("\n\a\t输入错误,请重新输入!\n"); 
            break; 
        } 
        scanf("%c",&c);                 //用来吸收多余字符 
        printf("\n\t按任意键继续,或按“n”退出!你的选择是:"); 
        scanf("%c",&c); 
        if(c=='n') 
        return 0; 
    } 
    return 0; 
}