二叉树的常见操作

#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>

//双亲表示法
#define MAX_TREE_SIZE 10
#define OK 1
#define ERROR 0
#define true 1
#define false 0
#define EOVERFLOW 0
typedef char ElemType;
typedef int bool;
typedef int Status;
enum TREEWAY
{
      PREORDER, INORDER, POSTORDER, LEVEL
};
enum TREEWAY treeWay = PREORDER;
char blankStr=' ';//空格


typedef struct _BTNode{
    ElemType data;
    struct _BTNode *lchild,*rchild;
}BiTNode,*BiTree;


//---------------栈(链表)相关开始----------------------
typedef BiTree SElemType;
typedef struct _SqNode{
    SElemType data;
    struct _SqNode *next;
}SqNode;
typedef struct _SqStack{
    SqNode *top;
    int count;//栈计数器
}SqStack;
void Init_Stack(SqStack *stack){
    stack->top=NULL;
    stack->count=0;
}
//压栈
Status Push(SqStack *stack,SElemType e){
    SqNode *node=NULL;
    do{
        node=(SqNode*)malloc(sizeof(SqNode));
    }while(!node);
    node->data=e;
    node->next=stack->top;
    stack->top=node;
    stack->count++;
    return OK;
}
//出栈 后进先出
Status Pop(SqStack *stack,SElemType *e){
    if(stack->top){
        SqNode *tmp=stack->top;
        stack->top=tmp->next;
        *e=tmp->data;
        free(tmp);
        stack->count--;
        return OK;
    }else{
        printf("栈为空,出栈失败\n");
        return ERROR;
    }
}
void Clear_Stack(SqStack *stack){
    if(!stack->top)return;
    SqNode *p=stack->top;
    SqNode *tmp;
    while(p){
        tmp=p;
        p=tmp->next;
        free(tmp);
    }
    stack->top=NULL;
    stack->count=0;
}
void Destory_Stack(SqStack *stack){
    Clear_Stack(stack);
    free(stack);
}
int Stack_IsEmpty(SqStack stack){
    if(stack.top){
        return false;
    }
    return true;
}

//---------------栈相关结束----------------------

//---------------队列(顺序结构,循环)相关开始----------------------
const int INIT_QUEUE_SIZE=100;
const int INCREAMENT_QUEUE_SIZE=2;
typedef BiTree QElemType;
typedef struct _SqQueue{
    int front;//对头
    int rear;//对尾
    QElemType *base;
    int size;
    int capacity;
}Queue;
Queue* Init_Queue(){
    Queue* q=(Queue*)malloc(sizeof(Queue));
    if(!q){
        return NULL;
    }
    q->base=(QElemType*)malloc(sizeof(QElemType)*INIT_QUEUE_SIZE);
    q->front=q->rear=0;
    q->size=0;
    q->capacity=INIT_QUEUE_SIZE;
    return q;
}
int Queue_IsFull(Queue *q){
    if(q->size==q->capacity){
        return true;
    }
    return false;
}
int Queue_IsEmpty(Queue *q){
    if(q->size==0){
        return true;
    }
    return false;
}
void Clear_Queue(Queue *queue){
    queue->front=queue->rear=0;
    queue->size=0;
}
void Destroy_Queue(Queue *queue){
    free(queue->base);
    queue->base=NULL;
}
//扩容  未完善
Queue* Copy_Queue(Queue *q){
    if(q->base==NULL){
        return q;
    }

    Queue* newQueue=(Queue*)malloc(sizeof(Queue));
    newQueue->base=(QElemType*)malloc(sizeof(QElemType)*(q->capacity+INCREAMENT_QUEUE_SIZE));
    newQueue->front=newQueue->rear=0;
    newQueue->size=0;
    newQueue->capacity=q->capacity+INCREAMENT_QUEUE_SIZE;
    int i,end,index=0;
    //队尾与对头相减大于0 则最大下标为队尾,否则下标为队列最大容量 可能存在重头开始情况
    bool flag=q->rear-q->front>0;
    if(flag){
        end=q->rear;
    }else{
        end=q->capacity;
    }
    for(i=q->front;i<end;i++){
        newQueue->base[index++]=q->base[i];
    }
    if(!flag){
        for(int j=0;j<q->rear;j++){
            newQueue->base[index++]=q->base[j];
        }
    }
    newQueue->size=q->size;
    return newQueue;
}

//入队列
void Push_Queue(Queue *q,QElemType e){
    //判断队列容量是否已经满了 重新分配
    if(Queue_IsFull(q)){
        printf("\n队列已满,无法入队\n");
        return ;
    }
    //将新元素赋值到队尾
    q->base[q->rear]=e;
    //重新设置队尾
    //获取下一个下标,取模 循环当下标到最大时,从0开始;
    int nextIndex=(q->rear+1)%(q->capacity);
    q->rear=nextIndex;
    q->size++;
}
void Pop_Queue(Queue *q,QElemType *e){
    //判断是否为空
    if(q->size==0){
        printf("队列为空,不能出队\n");
        return;
    }
    *e=q->base[q->front];
    int nexIndex=(q->front+1)%q->capacity;
    q->front=nexIndex;
    q->size--;
}


//---------------队列相关结束----------------------




//创建二叉树
void CreateBiTree(BiTree *Root){
    ElemType val=0;
    val=getchar();
    //如果输入' ',则指向为空
    if(val == blankStr){
        (*Root) = NULL;
    //如果输入非' ',则给数据域赋值
    }else{
        *Root = (BiTNode*)malloc(sizeof(BiTNode));//根节点
        if(!(*Root)){
            printf("创建节点失败,无法分配可用内存...");
            exit(EOVERFLOW);
        }else{
            (*Root)->data=val;
            //创建左子树
            CreateBiTree(&(*Root)->lchild);//左节点
            //创建右子树
            CreateBiTree(&(*Root)->rchild);//右节点
        }
    }
}
//判断二叉树是否为空
int BiTreeEmpty(BiTree T){
    if(T){
        return false;
    }
    return true;
}
int BiTreeDepth(BiTree T){
    if(!T){
        return 0;
    }
    //树的高度 = max(左子树的高度,右子树的高度) + 1
    int leftDepth = BiTreeDepth(T->lchild);
    int rightDepth = BiTreeDepth(T->rchild);
    return leftDepth >= rightDepth ? leftDepth + 1 : rightDepth + 1;
}

//获取树的叶子节点个数

int getLeafNum(BiTree T){
    if(!T){
        return 0;
    }
    if(!T->lchild && !T->rchild){
        return 1;
    }
    int num=0;
    num+=getLeafNum(T->lchild);
    num+=getLeafNum(T->rchild);
    return num;
}
//打印所有叶子节点
void  printLeaf(BiTree T){
    if(!T)return;
    //叶子节点 打印
    if(!T->lchild && !T->rchild){
        putchar(T->data);
        return;
    }
    printLeaf(T->lchild);
    printLeaf(T->rchild);
}
void Traverse(BiTree T,enum TREEWAY treeWay){
    if(T){
        //前序遍历
        //访问根结点 (V);
        //前序遍历左子树 (L);
        //前序遍历右子树 (R)
        if(treeWay==PREORDER){
            putchar(T->data);
            Traverse(T->lchild,treeWay);
            Traverse(T->rchild,treeWay);
        //中序遍历
        //前序遍历左子树 (L);
        //访问根结点 (V);
        //前序遍历右子树 (R)
        }else if(treeWay==INORDER){
            Traverse(T->lchild,treeWay);
            putchar(T->data);
            Traverse(T->rchild,treeWay);
        //后序遍历
        //前序遍历左子树 (L);
        //访问根结点 (V);
        //前序遍历右子树 (R)
        }else if(treeWay==POSTORDER){
            Traverse(T->lchild,treeWay);
            Traverse(T->rchild,treeWay);
            putchar(T->data);
        //层序遍历:
        //从树的第一层开始,从上而下逐层遍历,在同一层中,按从左到右顺序逐个访问;
        }else if(treeWay==LEVEL){
            //关键中间变量存放每一层的数据
            BiTree temp[100];
            int in=0,out =0;
            temp[in++]=T;
            //每次把这一层存入,然后输出的时候就把他的左右节点存入
            //例如一颗完全二叉树abcdefg  输出a的时候把bc放入,输出b的时候把b的孩子放入也就是de,再输出c并且放入孩子fg,依次这样,达到层序的要求
            while(in>out){
                if(temp[out]){
                    putchar(temp[out]->data);
                    temp[in++]=temp[out]->lchild;
                    temp[in++]=temp[out]->rchild;
                }
                out++;
            }
        }
    }
}
//以递归形式先序遍历二叉树
void PreOrderTraverse(BiTree T){
    Traverse(T,PREORDER);
}
//以递归形式中序遍历二叉树
void InOrderTraverse(BiTree T){
    Traverse(T,INORDER);
}
//以递归形式后序遍历二叉树
void PostOrderTraverse(BiTree T){
    Traverse(T,POSTORDER);
}
void LevelTraverse1(BiTree T){
    Traverse(T,LEVEL);
}
//层序遍历
void LevelTraverse(BiTree T){
    if(T){
        Queue *queue=Init_Queue();
        //根节点入队
        Push_Queue(queue,T);
        BiTree tmp;
        while(!Queue_IsEmpty(queue)){
            Pop_Queue(queue,&tmp);
            putchar(tmp->data);
            if(tmp->lchild){
                Push_Queue(queue,tmp->lchild);
            }
            if(tmp->rchild){
                Push_Queue(queue,tmp->rchild);
            }
        }


    }

}


//前序非递归遍历
void NoPreOrderTraverse(BiTree T){
    if(!T){
        fprintf(stdout, "树为空\n");
        return;
    }
    SqStack stack;//栈记录遍历过的左子树
    Init_Stack(&stack);
    BiTree tmp= T;

    while(tmp || !Stack_IsEmpty(stack)){
        //将tmp节点的左子树全部压入栈并打印,
        while(tmp){
            Push(&stack,tmp);
            putchar(tmp->data);
            tmp=tmp->lchild;
        }
        //到叶子结点后,出栈,获取右子树
        if(!Stack_IsEmpty(stack)){
            Pop(&stack, &tmp);
            //将 tmp 置为右节点
            tmp = tmp->rchild;
        }
        //继续循环 压入右子树的左子树。
    }
}

//中序非递归遍历
void NoInOrderTraverse(BiTree T){
    if(!T){
        fprintf(stdout, "树为空\n");
        return;
    }
    SqStack stack;
    Init_Stack(&stack);
    BiTree tmp= T;
    while(tmp || !Stack_IsEmpty(stack)){
        //将tmp节点的左子树压入栈
        while(tmp){
            Push(&stack,tmp);
            tmp=tmp->lchild;
        }
        //到叶子结点后,出栈,访问该栈顶结点并打印, 获取右子树
        if(!Stack_IsEmpty(stack)){
            Pop(&stack, &tmp);
            putchar(tmp->data);
            //将 tmp 置为右节点
            tmp = tmp->rchild;
        }
        //继续循环 压入右子树的左子树。
    }
}
//后序非递归遍历
//后序遍历中,要保证左孩子和右孩子都已被访问,并且左孩子在右孩子之前访问才能访问根结点
void NoPostOrderTraverse(BiTree T){
    if(!T){
        fprintf(stdout, "树为空\n");
        return;
    }
    SqStack stack;
    Init_Stack(&stack);
    BiTree cur;//当前节点
    BiTree pre=NULL;//前一次访问的结点
    BiTree tmp;
    //将根节点入栈
    Push(&stack, T);
    while(!Stack_IsEmpty(stack)){
        //获取当前节点
        cur=stack.top->data;
        //如果当前节点不存在左孩子和右孩子(相对的根节点),则可以直接访问它
        //或者 当前节点存在左孩子或右孩子,但是其左孩子和右孩子都已经被访问过 则可以直接访问它
        if((!cur->lchild && !cur->rchild)||(pre && (pre==cur->lchild||pre==cur->rchild))){
            putchar(cur->data);//如果当前结点没有孩子结点或者孩子结点都已被访问过
            Pop(&stack, &tmp);
            pre = cur;
        }else{
            //将当前节点的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子之前别访问,左孩子和右孩子都在根结点前面被访问
            if(cur->rchild){
                Push(&stack,cur->rchild);
            }
            if(cur->lchild){
                Push(&stack,cur->lchild);
            }
        }

    }
}
int main()
{
    BiTree tree=NULL;
    printf("请先序输入二叉树的节点数据: ");
    CreateBiTree(&tree);
    printf("\n前序遍历结果为:");
    PreOrderTraverse(tree);
    printf("\n中序遍历结果为:");
    InOrderTraverse(tree);
    printf("\n后序遍历结果为:");
    PostOrderTraverse(tree);
    printf("\n层序遍历结果为:");
    LevelTraverse1(tree);
    printf("\n树的深度为:%d\n",BiTreeDepth(tree));
    printf("\n树的叶子节点个数为:%d\n",getLeafNum(tree));
    printf("\n获取所有叶子节点结果为:");
    printLeaf(tree);

    printf("\n非递归前序遍历结果为:");
    NoPreOrderTraverse(tree);
    printf("\n非递归中序遍历结果为:");
    NoInOrderTraverse(tree);
    printf("\n非递归后序遍历结果为:");
    NoPostOrderTraverse(tree);
    return 0;
}

号为空格

ABD###CE##FG###


image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容