【数据结构】二叉树的创建及遍历(C语言实现)

非递归方法创建、递归遍历二叉树

程序代码:

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>

#include<stdlib.h>

#include<malloc.h>

#define MAXSIZE 10000

typedef struct BTreeNode{

    char data;

    struct BTreeNode* lChild;

    struct BTreeNode* rChild;

}BTreeNode;

typedef struct{

    BTreeNode* pdata[MAXSIZE];

    int top;

}Stack;

void InitStack(Stack* S){

    S->top = 0;

}

void Push(Stack* S, BTreeNode* T){

    S->pdata[S->top] = T;

    S->top++;

}

BTreeNode* Pop(Stack* S){

    if (S->top != 0){

         S->top--;

         return S->pdata[S->top];

    }

    else

         return NULL;

}

int StackEmpty(Stack* S) {

    if (S->top == 0) return 1;

    else return 0;

}

BTreeNode* GetTop(Stack* S){

    if (!StackEmpty(S)) return S->pdata[S->top-1];

    return NULL;

}

BTreeNode* Create(){

    Stack* S = (Stack*)malloc(sizeof(Stack));

    InitStack(S);

    //创建并初始化栈

    char str[MAXSIZE];

    scanf("%s", str);

    //创建字符数组并输入前序二叉树

    char* p;

    p = str;

    //创建指针指向正在操作字符

    BTreeNode* newnode = (BTreeNode*)malloc(sizeof(BTreeNode));

    if (newnode == NULL){exit(-1);}

    newnode->data = *p;

    newnode->lChild = NULL;

    newnode->rChild = NULL;

    p++;

    Push(S, newnode);

    //根节点入栈

    BTreeNode* root = newnode;

    //记录根节点

    int flag = 0;

    while (*p != '\0')

    {

         if (*p == '#' && flag == 0){

             flag = 1;

         }

         else if (*p == '#' && flag == 1)

         {

             BTreeNode* t = Pop(S);

             if (!StackEmpty(S)) {

                  while (GetTop(S)->rChild == t)

                  {

                      t = Pop(S);

                      if (StackEmpty(S))break;

                  }

             }

         }

         else

         {

             newnode = (BTreeNode*)malloc(sizeof(BTreeNode));

             if (newnode == NULL) { exit(-1); }

             newnode->data = *p;

             newnode->lChild = NULL;

             newnode->rChild = NULL;

             if (flag == 0)

             {

                  GetTop(S)->lChild = newnode;

                  Push(S, newnode);

             }

             else

             {

                  GetTop(S)->rChild = newnode;

                  flag = 0;

                  Push(S, newnode);

             }

         }

         p++;

    }

    return root;

}

void PrePrint(BTreeNode* T){

    if (T!=NULL)

    {

         printf("%c->", T->data);

         PrePrint(T->lChild);

         PrePrint(T->rChild);

    }

}

void InPrint(BTreeNode* T) {

    if (T != NULL)

    {

         InPrint(T->lChild);

         printf("%c->", T->data);

         InPrint(T->rChild);

    }

}

void PostPrint(BTreeNode* T) {

    if (T != NULL)

    {

         PostPrint(T->lChild);

         PostPrint(T->rChild);

         printf("%c->", T->data);

    }

}

int main()

{

    BTreeNode* root;

    printf("输入一组数据(以#分隔):\n");

    root = Create();

    printf("前序遍历:");

    PrePrint(root);

    printf("\n");

    printf("中序遍历:");

    InPrint(root);

    printf("\n");

    printf("后序遍历:");

    PostPrint(root);

    return 0;

}

运行截图:

 

非递归方法创建、非递归遍历二叉树

程序代码:

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>

#include<stdlib.h>

#include<malloc.h>

#define MAXSIZE 10000

typedef struct BTreeNode {

    char data;

    struct BTreeNode* lChild;

    struct BTreeNode* rChild;

}BTreeNode;

typedef struct {

    BTreeNode* pdata[MAXSIZE];

    int top;

}Stack;

void InitStack(Stack* S) {

    S->top = 0;

}

void Push(Stack* S, BTreeNode* T) {

    S->pdata[S->top] = T;

    S->top++;

}

BTreeNode* Pop(Stack* S) {

    if (S->top != 0) {

         S->top--;

         return S->pdata[S->top];

    }

    else

         return NULL;

}

int StackEmpty(Stack* S) {

    if (S->top == 0) return 1;

    else return 0;

}

BTreeNode* GetTop(Stack* S) {

    if (!StackEmpty(S)) return S->pdata[S->top - 1];

    return NULL;

}

BTreeNode* Create() {

    Stack* S = (Stack*)malloc(sizeof(Stack));

    InitStack(S);

    //创建并初始化栈

    char str[MAXSIZE];

    scanf("%s", str);

    //创建字符数组并输入前序二叉树

    char* p;

    p = str;

    //创建指针指向正在操作字符

    BTreeNode* newnode = (BTreeNode*)malloc(sizeof(BTreeNode));

    if (newnode == NULL) { exit(-1); }

    newnode->data = *p;

    newnode->lChild = NULL;

    newnode->rChild = NULL;

    p++;

    Push(S, newnode);

    //根节点入栈

    BTreeNode* root = newnode;

    //记录根节点

    int flag = 0;

    while (*p != '\0')

    {

         if (*p == '#' && flag == 0) {

             flag = 1;

         }

         else if (*p == '#' && flag == 1)

         {

             BTreeNode* t = Pop(S);

             if (!StackEmpty(S)) {

                  while (GetTop(S)->rChild == t)

                  {

                      t = Pop(S);

                      if (StackEmpty(S))break;

                  }

             }

         }

         else

         {

             newnode = (BTreeNode*)malloc(sizeof(BTreeNode));

             if (newnode == NULL) { exit(-1); }

             newnode->data = *p;

             newnode->lChild = NULL;

             newnode->rChild = NULL;

             if (flag == 0)

             {

                  GetTop(S)->lChild = newnode;

                  Push(S, newnode);

             }

             else

             {

                  GetTop(S)->rChild = newnode;

                  flag = 0;

                  Push(S, newnode);

             }

         }

         p++;

    }

    return root;

}

void PrePrint(BTreeNode* T) {

    Stack* S=(Stack*)malloc(sizeof(Stack));

    InitStack(S);

    BTreeNode* p = T;

    while (p != NULL || !StackEmpty(S)) {

         if (p) {

             printf("%c->", p->data);

             Push(S, p);

             p = p->lChild;

         }

         else {

             p = Pop(S);

             p = p->rChild;

         }   

    }

}

void InPrint(BTreeNode* T) {

    Stack* S = (Stack*)malloc(sizeof(Stack));

    InitStack(S);

    BTreeNode* p = T;

    while (p != NULL || !StackEmpty(S)) {

         if (p) {

             Push(S, p);

             p = p->lChild;

         }

         else {

             p = Pop(S);

             printf("%c->", p->data);

             p = p->rChild;

         }

    }

}

int main()

{

    BTreeNode* root;

    printf("输入一组数据(以#分隔):\n");

    root = Create();

    printf("前序遍历:");

    PrePrint(root);

    printf("\n");

    printf("中序遍历:");

    InPrint(root);

    return 0;

}

运行截图:

 

递归方法创建、递归遍历二叉树

程序代码:

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>

#include<stdlib.h>

#include<malloc.h>

typedef struct BTreeNode {

    char data;

    struct BTreeNode* lChild;

    struct BTreeNode* rChild;

}BTreeNode;

BTreeNode* Create() {

    BTreeNode* T;

    char ch;

    scanf("%c",&ch);

    if (ch == '#') T = NULL;

    else {

         T = (BTreeNode*)malloc(sizeof(BTreeNode));

         T->data = ch;

         T->lChild = Create();

         T->rChild = Create();

    }

    return T;

}

void PrePrint(BTreeNode* T) {

    if (T != NULL)

    {

         printf("%c->", T->data);

         PrePrint(T->lChild);

         PrePrint(T->rChild);

    }

}

void InPrint(BTreeNode* T) {

    if (T != NULL)

    {

         InPrint(T->lChild);

         printf("%c->", T->data);

         InPrint(T->rChild);

    }

}

void PostPrint(BTreeNode* T) {

    if (T != NULL)

    {

         PostPrint(T->lChild);

         PostPrint(T->rChild);

         printf("%c->", T->data);

    }

}

int main()

{

    BTreeNode* root;

    printf("输入一组数据(以#分隔):\n");

    root = Create();

    printf("前序遍历:");

    PrePrint(root);

    printf("\n");

    printf("中序遍历:");

    InPrint(root);

    printf("\n");

    printf("后序遍历:");

    PostPrint(root);

    return 0;

}

运行截图:

 

实验小结

非递归创建二叉树的算法思想

首先,我们对二叉树进行扩展,然后按先序遍历的顺序输入节点的信息,然后我们设置一个标志位flag,如果flag=0,创建当前节点的左孩子节点,当flag=1时,创建当前节点的右孩子节点。具体的分为以下四种情况:

1. 当前要创建的节点值为'#',并且flag=1,说明当前节点的父节点的左右孩子已经创建完毕,应将栈顶元素出栈,如果出栈的元素与栈顶的元素的右孩子相同,说明当前节点的父节点的左右孩子也创建完毕。栈顶元素继续出栈,直到栈顶的元素的右孩子和出栈的元素不相同。

2. 当前要创建的节点值'#',并且flag=0,说明当前节点的父节点的左孩子已经创建完毕,转向创建右孩子,把flag置为1;

3. 当前要创建的节点值不等于'#',并且flag=0,创建当前节点 并作为栈顶元素的左孩子,同时把当前节点入栈。(保存节点,创建右孩子)。

4. 当前要创建的节点值不等于'#',并且flag=1,创建当前节点并作为栈顶元素的右孩子。同时把当前节点入栈。

递归的本质是栈

我们知道递归函数存在的最大问题是,当递归次数足够大时,会导致函数栈溢出而死机,函数栈的大小一般是一个固定值,对于Linux来说一般默认是8M。因此,许多人说不得用递归函数。那么问题来了,所有递归函数都能非递归化吗?答案是肯定的。

本质上讲,对于同一个问题,如果必然要用广义递归的方案来处理,那么狭义递归函数只不过是其中的一种实现方式,如果放弃狭义递归函数的话,我们不得不借助一个额外的数据结构:栈。如此看来,无论如何都要用到栈,只不过要么让编译器来维护一个栈(函数栈),要么让程序员来维护一个栈(数据栈)。两者区别如下:

函数栈

数据栈

位置

进程的stack区

进程的heap区

大小限制

能分配到很大

每个栈“元素”所需空间

比较大,因为要存储函数上下文

可以设计到很小,比如只存储一个指针

栈开销

可以做到很小

代码简易程度

简洁易读

相对更复杂

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头鸭鸭鸭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值