二叉树的简单操作(Binary Tree)

树形结构应该是贯穿整个数据结构的一个比较重要的一种结构,它的重要性不言而喻!

讲到树!一般都是讨论二叉树,而关于二叉树的定义以及概念这里不做陈诉,可自行搜索。

在C语言里面需要实现一个二叉树,我们需要申明一个结构体,而关于其结构体的多种方法

这里也不一一列出,我采用比较通用的方法:

struct TreeNode{

    ElementType Element;

    struct TreeNode *Left;

    struct TreeNode *RIght;

};

BinaryTree.h:

#ifndef TREE_H
#define TREE_H

typedef char TreeElementType;

typedef struct TreeNode *PtrToNode;
typedef PtrToNode BinTree;

struct TreeNode
{
    TreeElementType Element;
    struct TreeNode *Left;
    struct TreeNode *Right;
};

BinTree CreateTree();//先序遍历创建二叉树
BinTree IterationCreateTree();//先序非递归创建二叉树

void PreOrderTraversal(BinTree BT);
void IterationPreOrderTraversal(BinTree BT);

void InOrderTraversal(BinTree BT);
void IterationInOrderTraversal(BinTree BT);

void PostOrderTraversal(BinTree BT);
void IterationPostOrderTraversal(BinTree BT);

void LevelTraversal(BinTree BT);

int SumNode(BinTree BT);
int SumLeafNode(BinTree BT);
int Depth(BinTree BT);//输出整个二叉树的深度

#endif

整个关于二叉树的操作函数都写了它的递归和迭代版本(层次遍历没有写递归版本),为了保持文件的封装性,将整个关于二叉树的简单操作都封装在一个.c文件里

TreeOperate.c:

#include"BinaryTree.h"
#include"Stack.c"
#include"Queue.c"
#include<stdio.h>
#include<stdlib.h>

#define MaxSize 50//栈和队列的大小

//先序递归创建二叉树
BinTree CreateTree()
{
    TreeElementType ch;
    BinTree BT;
    ch = getchar();
    if(ch == '0')
        BT = NULL;
    else
    {
        BT = (BinTree)malloc(sizeof(struct TreeNode));
        if(NULL == BT)
        {
            printf("Out of space!!!");
            return NULL;
        }
        BT->Element = ch;
        BT->Left = CreateTree();
        BT->Right = CreateTree();
    }
    return BT;
}
            
void PreOrderTraversal(BinTree BT)
{
    if(BT)
    {
        printf("%c ", BT->Element);
        PreOrderTraversal(BT->Left);
        PreOrderTraversal(BT->Right);
    }
}

void InOrderTraversal(BinTree BT)
{
    if(BT)
    {
        InOrderTraversal(BT->Left);
        printf("%c ", BT->Element);
        InOrderTraversal(BT->Right);
    }
}

void PostOrderTraversal(BinTree BT)
{
    if(BT)
    {
        PostOrderTraversal(BT->Left);
        PostOrderTraversal(BT->Right);
        printf("%c ", BT->Element);
    }
}


/*-------------------下面是非递归写法------------------------*/
//先序非递归创建二叉树
BinTree IterationCreateTree()
{
    int Flag[MaxSize] = {0};
    Stack S;
    S = CreatStack(MaxSize);
    TreeElementType ch;
    BinTree Root;
    PtrToNode NewCell, T;
    printf("请输入简单二叉树的元素类似:222003004500600:
");
    do{
        ch = getchar();
        if(ch == '0')
            NewCell = NULL;
        else
        {
            NewCell = (BinTree)malloc(sizeof(struct TreeNode));
            if(NULL == NewCell)
            {
                printf("Alloc is fairure!!");
                return NULL;
            }
            else
            {
                NewCell->Element = ch;
                NewCell->Left = NewCell->Right = NULL;
            }
        }
        //根节点入栈
        if(IsEmpty(S) && NewCell)
        {
            Push(S, NewCell);
            Root = NewCell;//第一个进栈的为根节点
            Flag[S->TopOfStack] = 0;
        }
        //如果当前(栈顶)节点已经连接左节点,现在连接右节点
        else if(Flag[S->TopOfStack] == 1)
        {
            T = TopAndPop(S);
            T->Right = NewCell;
            if(NewCell)
            {
                Push(S, NewCell);
                Flag[S->TopOfStack] = 0;//元素进栈后都要置为0,清除隐患
            }
        }
        //该左孩子节点入栈,并连接父亲节点
        else
        {
            Flag[S->TopOfStack] = 1;//父亲结点标记为1,表示已经连接左结点
            //下面是连接左结点的代码
            T = Top(S);
            T->Left = NewCell;
            if(NewCell)
            {
                Push(S, NewCell);
                Flag[S->TopOfStack] = 0;//元素进栈后都要置为0,清除隐患
            }
        }
    }while(!IsEmpty(S));

    return Root;
}
//先序
void IterationPreOrderTraversal(BinTree BT)
{
    Stack S;
    S = CreatStack(MaxSize);
    BinTree T = BT;
    while(T || !IsEmpty(S))
    {
        while(T)
        {
            Push(S, T);
            //注意printf的顺序,因为他是在访问左孩子节点时就已经处理了!
            printf("%c ", T->Element);
            T = T->Left;
        }
        if(T == NULL)
        {
            T = TopAndPop(S);
            T = T->Right;
        }
    }
}
//中序
void IterationInOrderTraversal(BinTree BT)
{
    Stack S;
    S = CreatStack(MaxSize);
    BinTree T = BT;
    while(T || !IsEmpty(S))
    {
        while(T)
        {
            Push(S, T);
            T = T->Left;
        }
        if(T == NULL)
        {
            T = TopAndPop(S);
            //printf在访问右孩子之前就处理的当前元素
            printf("%c ", T->Element);
            T = T->Right;
        }
    }
}
//后序
//void IterationPostOrderTraversal(BinTree BT)
//{
//    int Flag[MaxSize];
//    Stack S;
//    S = CreatStack(MaxSize);
//    BinTree T = BT;
//    while(T || !IsEmpty(S))
//    {
//        while(T)
//        {
//            Push(S, T);
//            Flag[S->TopOfStack] = 0;//未处理的标记为0
//            T = T->Left;
//        }
//        while(Flag[S->TopOfStack] == 1)
//        {
//            T = TopAndPop(S);
//            printf("%c ", T->Element);
//            T = NULL;//该节点被处理后,父亲节点的右孩子置空
//        }
//        if(!IsEmpty(S))
//        {
//            T = Top(S);
//            T = T->Right;
//          Flag[S->TopOfStack] = 1;
//        }
//    }
//}
//第二种版本
void IterationPostOrderTraversal(BinTree BT)
{
    int Flag[MaxSize] = {0};
    Stack S;
    S = CreatStack(MaxSize);
    BinTree T = BT;
    while(T || !IsEmpty(S))
    {
        /*将左结点全部入栈*/
        if(T)
        {
            Push(S, T);
            Flag[S->TopOfStack] = 0;//未处理的标记为0
            T = T->Left;
        }
        /*如果已经访问了该结点的右孩子,将它出队并打印*/
        else if(Flag[S->TopOfStack] == 1)
        {
            T = TopAndPop(S);
            printf("%c ", T->Element);
            T = NULL;//该节点被处理后置空,否则会被识别入栈
        }
        /*如果左孩子为空,则访问它的右孩子*/
        else
        {
            T = Top(S);
            T = T->Right;
            Flag[S->TopOfStack] = 1;//访问了右孩子,标记为1
        }
    }
}
//层次
void LevelTraversal(BinTree BT)
{
    Queue Q;
    Q = CreatQueue(MaxSize);
    BinTree T = BT;
    Enqueue(Q, T);
    while(!QIsEmpty(Q))
    {
        T = FrontAndDequeue(Q);
        printf("%c ", T->Element);
        if(T->Left)
            Enqueue(Q, T->Left);
        if(T->Right)
            Enqueue(Q, T->Right);
    }
}

int SumNode(BinTree BT)
{
    if(NULL == BT)
        return 0;
    else if(BT->Left == NULL && BT->Right == NULL)
        return 1;
    else
        return SumNode(BT->Left) + SumNode(BT->Right) + 1;//加1等于是每次返回 加一个根结点
}

int SumLeafNode(BinTree BT)
{
    if(NULL == BT)
        return 0;
    else if(BT->Left == NULL && BT->Right == NULL)
        return 1;
    else
        return SumLeafNode(BT->Left) + SumLeafNode(BT->Right);
}

int Depth(BinTree BT)//输出的是整个二叉树的深度
{
    int DepthOfLeft = 0;
    int DepthOfRight = 0;
    if(NULL == BT)
        return 0;
    else
    {
        DepthOfLeft = Depth(BT->Left);
        DepthOfRight = Depth(BT->Right);
        return (DepthOfLeft > DepthOfRight) ? DepthOfLeft + 1 : DepthOfRight + 1;
    }
}

上文用到的栈的操作和队列的操作出自https://www.cnblogs.com/Crel-Devi/p/9460945.html和https://www.cnblogs.com/Crel-Devi/p/9600940.html,需修改栈和队列同名的函数名称以及Element的名字以及栈和队列的元素类型!!!!!!!(非常重要)

下面给出一个简单的测试代码main.c:

#include"BinaryTree.h"
#include<stdio.h>
#include<stdlib.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
    BinTree BT;
    printf("请输入二叉树的元素:");
    BT = CreateTree();
    //BT = IterationCreateTree();

    printf("先序遍历(递归):	");
    PreOrderTraversal(BT);
    printf("
");
    printf("先序遍历(迭代):	");
    IterationPreOrderTraversal(BT);
    printf("

");

    printf("中序遍历(递归):	");
    InOrderTraversal(BT);
    printf("
");
    printf("中序遍历(迭代):	");
    IterationInOrderTraversal(BT);
    printf("

");

    printf("后序遍历(递归):	");
    PostOrderTraversal(BT);
    printf("
");
    printf("后序遍历(迭代):	");
    IterationPostOrderTraversal(BT);
    printf("

");
    
    printf("层次遍历(迭代):	");
    LevelTraversal(BT);
    printf("

");
    
    int allnode, leafnode, treedepth;
    allnode = SumNode(BT);
    leafnode = SumLeafNode(BT);
    treedepth = Depth(BT);
    printf("二叉树结点总数:%d	
", allnode);
    printf("二叉树叶节点总数:%d	
", leafnode);
    printf("二叉树深度:%d	
", treedepth);//输出整棵树的深度
    printf("
");

    return 0;
}

原文地址:https://www.cnblogs.com/Crel-Devi/p/9683585.html