二叉树的基本操作

二叉树的基本操作

1、定义二叉树的数据结构,包含数据域,左子树和右子树

```cpp
#include <stdio.h>
#include <stdlib.h>
#include<stack>
using namespace std;
typedef  struct BTNode{
    int data;
    struct BTNode *lChild;
    struct BTNode *rChild;
}BiTNode;

2、创建二叉树的基本函数

//先序创建二叉树,递归实现
void CreateBiTree(BiTNode **T){
    int ch;
    scanf("%d",&ch);
    if(ch==-1){
        *T=NULL;
        return;
    }else{
        *T=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->data=ch;
        printf("输入%d左子结点",ch);
        //scanf("%d",&ch);
        CreateBiTree(&((*T)->lChild));
        printf("输入%d右子结点",ch);
        //scanf("%d",&ch);
        CreateBiTree(&((*T)->rChild));
    }
    return;
}
//先序遍历二叉树,递归
void PreOrderBiTree(BiTNode *T){
    if(T==NULL) return;
    else{
        printf("%d",T->data);
        PreOrderBiTree(T->lChild);
        PreOrderBiTree(T->rChild);
    }
}
//中序遍历二叉树,递归
void MiddleOrderBiTree(BiTNode *T){
    if(T==NULL) return;
    else{
        MiddleOrderBiTree(T->lChild);
        printf("%d",T->data);
        MiddleOrderBiTree(T->rChild);
    }
}
//后序遍历二叉树,递归
void PostOrderBiTree(BiTNode *T){
    if(T==NULL) return;
    else{
        PostOrderBiTree(T->lChild);
        PostOrderBiTree(T->rChild);
        printf("%d",T->data);
    }
}
//先序遍历二叉树,栈
void PreOrderTraverse(BiTNode *T){ //严蔚敏数据结构中的算法
    stack<BiTNode*> S;
    BiTNode* p;
    p=T;
    while(p||!S.empty()){
        if(p){
            printf("%d",p->data);
            S.push(p);
            p=p->lChild;
        }else{
            p=S.top();
            S.pop();
            p=p->rChild;
        }
    }
}
void preTraversal(BiTNode* T){  //个人感觉用while循环更容易实现
    if(T==NULL)return;
    BiTNode*p=T;
    stack<BiTNode*>S;
    S.push(p);
    while(!S.empty()){
        p = S.top();
        printf("%d",p->data);
        S.pop();
        if(p->rChild!=NULL)
            S.push(p->rChild);
        if(p->lChild!=NULL)
            S.push(p->lChild);
    }
}
//中序遍历二叉树,栈
void InOrderTraverse(BiTNode *T){  //课本算法
    stack<BiTNode*> S;
    BiTNode* p;
    p=T;
    //根指针进栈,遍历左子树
    while(p||!S.empty()){
        if(p) {
            S.push(p);
            p = p->lChild;
        }else{   //根指针退栈,访问根节点,遍历右子树
            p=S.top();
            S.pop();
            printf("%d", p->data);
            p=p->rChild;
        }
    }
}
void inorderTraversal(BiTNode *T){   //while高级算法
    if(T==NULL)return;
    stack<BiTNode*> S;
    S.push(T);
    while(!S.empty()){
        //该过程一直找到没有左节点的节点才停止
        while(S.top()->lChild!=NULL){
            S.push(S.top()->lChild);
        }
        //此时的S.top()是一个没有left的节点,按照中序遍历的特性,可以将其直接输出。
        //while循环会一直将栈顶输出,直到遇到有右节点的节点,这样能保证栈中元素不会重复寻找左孩子
        while(!S.empty()){
            BiTNode *p = S.top();
            printf("%d",p->data);
            S.pop();
            if(p->rChild){
                S.push(p->rChild);
                break;
            }
        }
    }
}
//后序遍历二叉树,栈
/*
1、如果栈顶元素非空且左节点存在,将其入栈,重复该过程。若不存在则进入第2步(该过程和中序遍历一致)
2、判断上一次出栈节点是否当前节点的右节点,或者当前节点是否存在右节点,满足任一条件,将当前节点输出,并出栈。否则将右节点压栈。跳至第1步
 */
void PostOrderTraverse(BiTNode *T){
    stack<BiTNode*>S;
    S.push(T);
    BiTNode* lastPopNode=NULL;
    while(!S.empty()){
        while(S.top()->lChild!=NULL){   //向左走到尽头
            S.push(S.top()->lChild);
        }
        while(!S.empty()){
            if(lastPopNode==S.top()->rChild||S.top()->rChild==NULL){  //如果栈顶右节点指针为空,或者是上一次出栈结点的右节点,则输出
                printf("%d",S.top()->data);
                lastPopNode=S.top();
                S.pop();
            }
            else if(S.top()->rChild){        //如果栈顶指针有右节点,右节点入栈,结束当前循环
                S.push(S.top()->rChild);
                break;
            }
        }
    }
}
void posordertraverse(BiTNode *T){ //课本算法
    stack<BiTNode*> S;
    int StackMark[100];  //模拟栈,用于标志访问次数
    int k=-1;     //模拟栈的顺序
    BiTNode* p;
    p=T;
    while(1){
        while(p){    //向左走到尽头
            S.push(p);
            k++;       //标志栈,用于标志访问到的元素
            StackMark[k]=1;         //向左是第一次访问,访问次数为1
            p=p->lChild;
        }
        while(!p&&!S.empty()){
            p=S.top();
            if(StackMark[k]==1){           //已访问过一次,当前是第二次访问
                StackMark[k]=2;             //标志数记为2,访问右结点
                p=p->rChild;
            }else{                           //已访问过两次,当前是第三次访问
                printf("%d",p->data);       //第三次访问时打印元素
                StackMark[k]=0;                     //该标志位记为0
                k--;                                 //退栈
                S.pop();
                p=NULL;                           //为了继续取栈顶元素,将p置位空
            }
        }
        if(S.empty()) break;
    }
}
//二叉树d深度
int TreeDeep(BiTNode *T){
    int deep=0;
    if(T!=NULL){
        int leftdeep=TreeDeep(T->lChild);
        int rightdeep=TreeDeep(T->rChild);
        deep=leftdeep>=rightdeep?leftdeep+1:rightdeep+1;
    }
    return deep;
}
//叶子结点个数
int LeafCount(BiTNode *T){
    static int count;
    if(T!=NULL){
        if(T->rChild==NULL&&T->lChild==NULL)
            count++;
    LeafCount(T->lChild);
    LeafCount(T->rChild);
    }
    return count;
}
//二叉树所有结点在左右子树互换
void SwapTree(BiTNode **T){
    if(*T==NULL) return;
    if((*T)->lChild==NULL&&(*T)->rChild==NULL){
        return;
    }else{
        BiTNode *p, *q, *t;
        p = (*T)->lChild;
        q = (*T)->rChild;
        (*T)->rChild=p;
        (*T)->lChild=q;
        SwapTree(&p);
        SwapTree(&q);
    }
}
//先序序列和中序序列构造二叉树
void PreInOrd(int preord[],int inord[],int i,int j,int k,int h,BiTNode **T){
    //先序序列从i到j,中序序列从k到h,建立一颗二叉树放在t中
    int m;
    (*T)=(BiTNode*)malloc(sizeof(BiTNode));
    (*T)->data=preord[i];  //二叉树的根
    m=k;
    while(inord[m]!=preord[i])  m++;       //在中序序列中定位树根
    if(m==k)
        (*T)->lChild=NULL;      //左子树空
    else
        PreInOrd(preord,inord,i+1,i+m-k,k,m-1,&((*T)->lChild));  //递归调用建立左子树
    if(m==h)
        (*T)->rChild=NULL;   //右子树空
    else
        PreInOrd(preord,inord,i+m-k+1,j,m+1,h,&((*T)->rChild));     //递归调用建立右子树
}
//后序序列和中序序列构造二叉树
void PosInOrd(int posord[],int inord[],int i,int j,int k,int h,BiTNode **T){
    int m;
    (*T)=(BiTNode*)malloc(sizeof(BiTNode));
    (*T)->data=posord[j];
    m=k;
    while(posord[j]!=inord[m])  m++;   //中序序列中定位根的位置
    if(m==h)
        (*T)->rChild=NULL;         //右子树空
    else
        PosInOrd(posord,inord,j-h+m,j-1,m+1,h,&((*T)->rChild));         //递归调用建立右子树
    if(m==k)
        (*T)->lChild=NULL;        //左子树空
    else
        PosInOrd(posord,inord,i,j-h+m-1,k,m-1,&((*T)->lChild));           //递归调用建立左子树
}
//层次遍历
void LevelOrder(BiTNode *T)
{
    queue<BiTNode*> Queue;
    BiTNode* p;
    if(T==NULL) return;
    Queue.push(T);                    //根节点入队列
    while(!Queue.empty()){
        p=Queue.front();
        printf("%d",p->data);
        Queue.pop();
        if(p->lChild){                    //如果有左孩子,左孩子入队
            Queue.push(p->lChild);
        }
        if(p->rChild){                      //如果有右孩子,右孩子入队
            Queue.push(p->rChild);
        }
    }
}
//层次序列和中序序列构建二叉树
typedef struct{
    int lel;		//指向当前处理的元素在层次序列中的位置
    int low,high;	//中序序列的上下界
    BiTNode *parent;		//层次序列中当前结点的双亲结点指针
    int lr;			//判断左右子树,1为左,2为右
}Sq;
void LevelInOrd(int levelord[],int inord[],int n,BiTNode **T){    //有n个元素
    Sq q;
    queue <Sq> Q;
    if(n<1)
        T=NULL;	//二叉树为空
    else
    {
        int i, s;
        i = s = 0;    //s指向层次序列中当前处理的元素,i用来寻找当前处理的元素在中序序列中的位置
        *T = (BiTNode *) malloc(sizeof(BiTNode));
        (*T)->data = levelord[0];
        (*T)->lChild = NULL;
        (*T)->rChild = NULL;
        while (inord[i] != levelord[0])
            i++;                                 //寻找当前元素在中序序列中的位置
        if (i == 0 && i == n - 1) return;    //只有一个根节点
        //处理除根节点外的第一个节点
        if (i == 0)    //没有左子树
        {
            (*T)->lChild = NULL;
            q.lel = ++s;
            q.low = 1;
            q.high = n - 1;
            q.lr = 2;
            q.parent = (*T);
            Q.push(q);
        } else if (i == n - 1)    //没有右子树
        {
            (*T)->rChild = NULL;
            q.lel = ++s;
            q.low = 0;
            q.high = i - 1;
            q.lr = 1;
            q.parent = (*T);
            Q.push(q);
        } else {
            q.lel = ++s;
            q.low = 0;
            q.high = i - 1;
            q.lr = 1;
            q.parent = (*T);
            Q.push(q);
            q.lel = ++s;
            q.low = i + 1;
            q.high = n - 1;
            q.lr = 2;
            q.parent = (*T);
            Q.push(q);
        }
        while(!Q.empty())
        {
            q=Q.front(); Q.pop();
            BiTNode* fat=q.parent;
            i=q.low;
            BiTNode* p=(BiTNode*)malloc(sizeof(BiTNode));
            p->data=levelord[q.lel];
            p->lChild=p->rChild=NULL;
            if(q.lr==1)
                fat->lChild=p;
            else
                fat->rChild=p;          //连接当前节点与双亲节点
            while(inord[i]!=levelord[q.lel])    //寻找当前元素在中序序列中的位置
                i++;
            if(i==q.low && i==q.high)	//叶子结点,无孩子
            {
                p->lChild=p->rChild=NULL;
                continue;
            }
            else if(i==q.low)	//没有左孩子
            {
                p->lChild=NULL;
                q.lel=++s;	q.low=i+1;	q.parent=p; q.lr=2;   //处理下一个元素,q.high不变
                Q.push(q);
            }
            else if(i==q.high)	//没有右孩子
            {
                p->rChild=NULL;
                q.lel=++s;	q.high=i-1;	q.parent=p; q.lr=1; //处理下一个元素,q.low不变
                Q.push(q);
            }
            else
            {
                int high=q.high;	//备份一下
                q.lel=++s;	q.high=i-1;	q.parent=p; q.lr=1;
                Q.push(q);
                q.lel=++s;	q.low=i+1; q.high=high;	q.parent=p; q.lr=2;
                Q.push(q);
            }
        }
    }
}

3、测试函数

int main() {
    BiTNode *T;
    int depth,leafCount=0;

    printf("请输入第一个节点的值,-1表示没有结点:\n");
    CreateBiTree(&T);

    printf("栈方法先序遍历二叉树");
    PreOrderTraverse(T);
    printf("\n");

    printf("栈方法中序遍历二叉树");
    InOrderTraverse(T);
    printf("\n");

    printf("栈方法后序遍历二叉树");
    PostOrderTraverse(T);
    printf("\n");

    printf("栈方法后序遍历二叉树,使用标志栈");
    posordertraverse(T);
    printf("\n");

    printf("递归先序遍历二叉树");
    PreOrderBiTree(T);
    printf("\n");

    printf("递归中序遍历二叉树");
    MiddleOrderBiTree(T);
    printf("\n");

    printf("递归后序遍历二叉树");
    PostOrderBiTree(T);
    printf("\n");

 	printf("层次遍历二叉树");
    LevelOrder(T);
    printf("\n");

    depth=TreeDeep(T);
    printf("树的深度:%d\n",depth);

    leafCount=LeafCount(T);
    printf("叶子结点个数:%d\n",leafCount);

    printf("交换二叉树的左右子树,");
    SwapTree(&T);
    printf("先序遍历结果为");
    PreOrderBiTree(T);
    printf("\n");

    printf("由先序和中序序列构建二叉树,");
    BiTNode* t;
    int pre[7]={1,2,3,4,5,6,7};
    int in[7]={3,2,4,1,5,7,6};
    PreInOrd(pre,in,0,6,0,6,&t);
    printf("先序输出结果:");
    PreOrderBiTree(t);
    printf("\n");

    printf("由后序和中序序列构建二叉树,");
    BiTNode* f;
    int pos[8]={4,5,3,2,8,7,6,1};
    int inn[8]={2,4,3,5,1,6,8,7};
    PosInOrd(pos,inn,0,7,0,7,&f);
    printf("先序输出结果:");
    PreOrderBiTree(f);
    printf("\n");
    
	printf("由层次和中序序列构建二叉树,");
    BiTNode* ff;
    int lev[10]={1,2,3,4,5,6,7,8,9,10};
    int innn[10]={4,2,7,5,8,10,1,3,9,6};
    LevelInOrd(lev,innn,10,&ff);
    printf("先序输出结果:");
    PreOrderBiTree(ff);
    printf("\n");

    return 0;
}
//测试数据 p125页图6.4  1 2 4 -1 -1 5 6 -1 -1 7 -1 -1 3 -1 -1

4、输出结果
在这里插入图片描述

  • 12
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值