C数据结构与算法-基础整理-树-02:二叉树的建立及四种遍历方式

树-02:二叉树的建立及四种遍历方式

整理了完全二叉树的建立方法以及四种遍历方式(多种方法实现)

在理解本章后,可查看:
C数据结构与算法-基础整理-树-03:图解-通过前序遍历对递归执行原理的深入理解
C数据结构与算法-基础整理-树-04:图解-树的中序遍历
C数据结构与算法-基础整理-树-05:图解-树的后序遍历

在保证结构定义一样的前提下,代码可通用。

0x01.二叉树的结构定义:

typedef struct TreeNode
{
    char data;
    struct TreeNode* Left;//左孩子指针
    struct TreeNode* Right;//右孩子指针
}TreeNode,*BinTree;//定义了这个结构体为 TreeNode ,这个二叉树指针为 BinTree

0x02.二叉树的建立:

简单一点:直接输入一个数据创建一个结点

具体注释见下一个。

void CtreateBiTree(BinTree *BT)
{
    char ch;
    scanf("%c",&ch);
    if(ch=='#')
    {
        *BT=NULL;
    }
    else
    {
        *BT=(BinTree)malloc(sizeof(TreeNode));
        if(!BT)
            exit(-1);
        (*BT)->data=ch;
        CreateBiTree(&(*BT)->Left);
        CreateBiTree(&(*BT)->Right);
    }
 }

复杂一点:引用字符串来创建二叉树

//二叉树的建立:递归实现,先序遍历的创建方法
//注意此处BT为指针的指针,因为没有返回值,所以要把二叉树的指针完全改变掉,需要指针的指针
//str为传入的字符串,该字符串用于创建二叉树的数据域
//n为当前创建节点数据域时使用到str的位数
//返回值为记录二叉树创建完毕后,使用了多少字符
//一定需要输入合法的用于创建树的字符串数据,不然会出错
int CreateBiTTree(BinTree *BT,char *str,int n)
{
    printf("创建二叉树第  %d  个节点   ", n);
    char ch = str[n];//每次使用一个字符赋值数据域
    printf("%c\n", ch);//输出该数据
    n++;
    if (ch != '\0')//字符串没完就一直创建
    {
        if (ch == '#')//如果遇到字符 # ,说明下方没有了,是叶节点
        {
            *BT = NULL;//代表二叉树指针为空
        }
        else
        {
            *BT = (BinTree)malloc(sizeof(TreeNode));//*BT代表二叉树指针的值,BinTree表示这是一个指针,大小为一个二叉树结构体
            if (!*BT)
            {
                exit(-1);//若分配空间失败,异常退出
            }
            (*BT)->data = ch;
            n=CreateTree(&(*BT)->Left,str, n);//取指针的地址给此函数的第一个参数,因为此参数为二级指针
            n=CreateTree(&(*BT)->Right, str, n);
        } 
    }
 return n;
}

0x03.二叉树的遍历

前序遍历:

遍历顺序说明:

先遍历所有的左子树,然后再遍历右子树。

用递归实现思路:

每遇到一个结点,先打印信息,再依次向左递归,向右递归。

用栈实现的思路:

用栈保存自己和自己的左孩子已经访问过的结点,然后出栈继续访问右孩子。
每遇到一个结点,先入栈,然后打印信息,然后去遍历它的左孩子,等左孩子遍历完成返回后,出栈,访问右孩子。

遍历顺序图解:

在这里插入图片描述

递归实现:
//前序遍历,递归实现
void PreorderTraversal(BinTree BT)
{
    if (BT == NULL) return;
    printf(" %c", BT->data);
    PreorderTraversal(BT->Left);
    PreorderTraversal(BT->Right);
    return;
}
栈实现:
//前序遍历,栈实
//栈中元素分析:栈中保留的元素是自己和自己的左孩子已经访问过来,但右孩子还没访问的结点
void PreorderTraversal1(BinTree BT)
{
    if (BT == NULL) return;
    BinTree Stack[100];//存储结点的栈
    int top = -1;
    BinTree p = BT;//p指针用于遍历
    while (p || top != -1)//退出循环条件为BT不存在且栈为空
    {
        if (p)
        {
            Stack[++top] = p;//如果BT存在,那么BT入栈
            printf(" %c", p->data);//打印信息
            p = p->Left;//继续访问左孩子
        }
        else
        {
            p = Stack[top--];//若访问到空,则拿出栈的一个元素,此元素的自己和左孩子已遍历,现在开始遍历右孩子
            p = p->Right;
        }
    }
}

中序遍历:

遍历顺序说明:

从根结点开始,一直到最左端的叶结点,开始访问该结点,然后再访问父亲,当父亲的所有左孩子访问完,再访问右孩子。

用递归实现的思路:

一直向左找到最左端的结点,等所有左端结点打印完,再去访问右孩子。

用栈实现的思路:

用栈保存自己和自己的右孩子都没有访问过的结点。
每遇到一个结点,先入栈,然后向左遍历,当左边没有了,再打印该节点信息,再向右遍历,反复循环,一直到所有元素访问完成。

遍历顺序图解:

在这里插入图片描述

递归实现:
//中序遍历,递归实现
void InorderTraversal(BinTree BT)
{
    if (BT == NULL) return;
    InorderTraversal(BT->Left);
    printf(" %c", BT->data);
    InorderTraversal(BT->Right);
    return;
}
//中序遍历,栈实现
//栈中元素分析:栈中保留的元素是自己和自己的右孩子都没访问过的结点
void InorderTraversal(BinTree BT)
{
    if (BT == NULL) return;
    BinTree Stack[100];
    int top = -1;
    BinTree p = BT;//p指针用于遍历
    while (p || top != -1)//退出循环条件为BT不存在且栈为空
    {
           if (p)
           {
               Stack[++top] = p;//如果BT存在,那么BT入栈
               p = p->Left;//继续访问左孩子
           }
           else
           {
               p = Stack[top--];//若访问到空,则拿出栈的一个元素,此元素的左孩子已遍历,现在开始遍历右孩子
               printf(" %c", p->data);//打印信息
               p = p->Right;
           }
    }
}

后序遍历:

遍历顺序说明:

从左到右,先叶子,后结点。

用递归实现思路:

将左孩子,右孩子全部递归完成再打印具体信息。

用栈实现思路:

设置一个标志栈,用于保存结点栈的标志量,是第几次返回。
每遇到一个结点,先向左去找,置标志量为1,然后从左孩子遍历完退回来之后,置标志量为2,然后去遍历右孩子,从右孩子返回后,打印栈中结点信息,再将该结点出栈。

遍历顺序图解:

在这里插入图片描述

递归实现:
//后序遍历,递归实现
void PostorderTraversal(BinTree BT)
{
    if (BT == NULL) return;
    PostorderTraversal(BT->Left);
    PostorderTraversal(BT->Right);
    printf(" %c", BT->data);
    return;
}
栈实现:
//后序遍历,栈实现
//栈中元素分析:右孩子和自身都没有访问过的元素,第一次访问,继续访问左孩子,第二次访问,继续向右孩子访问,等左右孩子都访问完了,访问自身
void PostorderTraversal1(BinTree BT)
{
    if (BT == NULL) return;
    BinTree Stack[100];
    int top = -1;
    int flagStack[100];//此栈用于记录访问结点的次数,访问一次记1,访问两次记2,第三次访问输出结点值。
    BinTree p = BT;
    while (p || top != -1)
    {
        if (p)//第一次访问结点,flag=1
        {
            Stack[++top] = p;
            flagStack[top] = 1;
            p = p->Left;
        }
        else
        {
            if (flagStack[top] == 1)//第二次访问,说明从左孩子退回,继续去访问右孩子,取出栈中元素,但不出栈
            {
                p = Stack[top];
                flagStack[top] = 2;
                p = p->Right;
            }
            else//不等于1,那么一定是第三次访问,从右孩子退回,该输出自己的元素值了。
            {
                p = Stack[top--];
                printf(" %c", p->data);//打印信息
                p = NULL;//说明此结点的左右孩子均已完成遍历,那么将p置空,继续回退。
            }
        }
    }
}

层序遍历–队列实现

遍历顺序说明:

从根结点开始,一层一层,从左到右访问。

队列实现思路:

每遇到一个元素先打印信息,然后入队,若左孩子存在,则左孩子入对,右孩子存在,则右孩子后入队,等队中没有元素,就是全部遍历完成。

遍历顺序说明:

在这里插入图片描述

//层序遍历,队列实现
//队中元素分析:自身访问过,左右孩子未访问过
void LevelorderTraversal(BinTree BT)
{
    BinTree Queue[100];//创建一个二叉树指针类型的队列
    int head = -1;
    int tail = -1;
    if (BT)
    {
        Queue[++tail] = BT;//如果头结点非空,头结点入队
    }
    while (head < tail)//队列为空是遍历完成的条件
    {
        BinTree tmp = Queue[++head];//队头出队,打印信息
        printf("%c -> ", tmp->data);
        if (tmp->Left)//如果左孩子存在,左孩子先入队
        {
            Queue[++tail] = tmp->Left;
        }
        if (tmp->Right)
        {
            Queue[++tail] = tmp->Right;
        }
    }
}

0x04.写主函数测试

#include<stdio.h>
#include<stdlib.h>
int main()
{
   BinTree BT;//注意BT为指针
   int k;//记录创建函数的返回值
   char str[100];
   printf("\n\n**********\t请输入一串字符用于创建二叉树:");
   gets_s(str);
   k = CreateTree(&BT, str, 0);
   printf("\n\n**********\t二叉树创建成功!!!共使用了  %d  个字符",k);
   printf("\n\n**********\t开始该二叉树的前序遍历......");
   PreorderTraversal(BT);
   printf("\n\n**********\t开始该二叉树的中序遍历......");
   InorderTraversal(BT);
   printf("\n\n**********\t开始该二叉树的后序遍历......");
   PostorderTraversal(BT);
   printf("\n\n**********\t开始该二叉树的层序遍历......");
   LevelorderTraversal(BT);
   return 0;
}

测试数据:AB#D##C##
测试截图:
在这里插入图片描述

此章完结。
发布了19 篇原创文章 · 获赞 7 · 访问量 425

猜你喜欢

转载自blog.csdn.net/ATFWUS/article/details/104262585