二叉树非递归先序、中序、后序遍历的完整C实现

1.介绍

本文使用C语言完整实现二叉树的非递归先序、中序、后序遍历。

以下是原递归算法(二叉树的先序、中序、后序遍历的递归实现算法):

// 1.先序递归实现算法
void PreOrder(BiTree T) {
	if (T != NULL) {
		visit(T);
		PreOrder(T->lchild);
		PreOrder(T->rchild);
	}
}

// 2.中序递归实现算法
void InOrder(BiTree T) {
	if (T != NULL) {
		InOrder(T->lchild);
		visit(T);
		InOrder(T->rchild);
	}
}

// 3.后序递归实现算法
void PostOrder(BiTree T) {
	if (T != NULL) {
		PostOrder(T->lchild);
		PostOrder(T->rchild);
		visit(T);
	}
}

2.实现非递归完整版本(2021-04-06更)

栈和树的数据结构的头文件如下:

//
// Created by TAYNPG on 2021/4/5.
//

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


/*
 * --->>>>>>本头文件中的结构体及对应操作的约定:
 * 1.所有涉及判断是否执行成功的函数的返回值,统一规为返回 0 值成功,其他值 失败
 * 2.所有涉及真假的函数,返回值统一规为 1 真,0 值假
 *
 * */


#ifndef ONE_STRUCT_H
#define ONE_STRUCT_H

// **************************************
// 栈 -- 开始
// **************************************
// 栈内数据域类型
typedef void * StackDataType;
// 模拟栈结构
typedef struct Stack {
    StackDataType data;
    struct Stack* next;
}MyStack;

// 初始化栈顶指针(该指针也需要释放空间)。
int StackInit(MyStack **head) {

    *head = (MyStack *)malloc(sizeof(MyStack));

    if ((*head) != NULL) {
    
        (*head)->data = NULL;
        (*head)->next = NULL;
        
        return 0;
    }
    return -1;
}

// 入栈操作。
int StackPush(MyStack** head, StackDataType data) {

    MyStack* tmp = (MyStack *)malloc(sizeof(MyStack));
    if (tmp == NULL) {
        return -1;
    }

    tmp->next = (*head)->next;
    tmp->data = data;
    (*head)->next = tmp;

    return 0;
}

// 出栈操作, 并将值保存到 p。
int StackPop(MyStack** head, StackDataType* p) {

    if ((*head)->next == NULL) {
        return -1;
    }

    MyStack* tmp = (*head)->next;
    (*head)->next = tmp->next;
    *p = tmp->data;
    free(tmp);

    return 0;
}

// 栈是否为空,返回 1 为真。
int StackEmpty(MyStack* head) {
    if (!head || head->next == NULL)
        return 1;
    return 0;
}

// 查看栈顶结点的数据,不出栈。
StackDataType StackTop(MyStack* head) {

    if (head == NULL || head->next == NULL) {
        return NULL;
    }
    return head->next->data;
}

// 打印整个栈的数据,可复制出去修改后使用。
/*
void StackPrint(MyStack* head) {

    if (!head) return;
    MyStack* tmp = head->next;

    if (tmp == NULL) {
        printf("栈为空。\n");
        return ;
    }

    printf("打印内容的左侧为栈顶。\n");
    while (tmp != NULL) {
        printf("%d ", *(int *)tmp->data); // 修改这一行
        tmp = tmp->next;
    }

    printf("\n");
}
 */

// 释放栈空间。
void StackFree(MyStack* head) {

    if (!head) return;
    MyStack* ms = head->next;
    while(ms != NULL) {
        MyStack* temp = ms;
        ms = ms->next;
        free(temp);
    }
    free(head);
}
// **************************************
// 栈 -- 结束
// **************************************

// **************************************
// 树 -- 开始
// **************************************

// 树的数据域 数据类型
typedef void * TreeDataType ;

// 二叉树结构
typedef struct TreeNode {
    TreeDataType data;
    struct TreeNode* lchild;
    struct TreeNode* rchild;
}MyTree;

// 树结点的添加位置
enum Direction {
    LEFT = 1,
    RIGHT
}TreeDirection;

// 初始化树的根节点。
int TreeInit(MyTree** root, TreeDataType data) {

    *root = NULL;
    MyTree* tmp = (MyTree *)malloc(sizeof (MyTree));
    if (tmp == NULL) {
        return -1;
    }
    tmp->data = data;
    tmp->lchild = NULL;
    tmp->rchild = NULL;
    *root = tmp;

    return 0;
}

// 添加树结点,返回新结点的指针,如果返回值为NULL,表示添加失败。
// 失败原因可能为:
// 1.传入的父结点为空。
// 2.要添加的位置已经有结点。
// 3.传入的方向有错误。
MyTree* TreeAddNode(MyTree* parent, TreeDataType data, enum Direction direction) {

    if (parent == NULL) return NULL;
    MyTree* tmp = NULL;

    switch (direction) {
        case LEFT:
            if (parent->lchild != NULL) return NULL;
            tmp = (MyTree *)malloc(sizeof (MyTree));
            tmp->data = data;
            tmp->lchild = NULL;
            tmp->rchild = NULL;
            parent->lchild = tmp;
            break;

        case RIGHT:
            if (parent->rchild != NULL) return NULL;
            tmp = (MyTree *)malloc(sizeof (MyTree));
            tmp->data = data;
            tmp->lchild = NULL;
            tmp->rchild = NULL;
            parent->rchild = tmp;
            break;

        default:
            return NULL;
    }

    return tmp;
}

// 查看树结点的值,可复制出去修改后使用。
/*
void TreeNodeVisit(MyTree* root) {

    if (root == NULL) {
        printf("树为空。\n");
        return;
    }

    printf("%c ", *(char *)root->data); // 修改这一行
}
 */

// 释放树空间,请传入树的根结点完全释放。
void FreeTree(MyTree* root) {

    if (root != NULL) {
        FreeTree(root->lchild);
        FreeTree(root->rchild);
        free(root);
    }
}

// **************************************
// 树 -- 结束
// **************************************


#endif //ONE_STRUCT_H

main函数

下面在main函数中手动生成一个树,用于测试,树的结构如下:
在这里插入图片描述
按照上图所示,构造这样的一棵树:

#include "MyStruct.h"

// 这里写三个遍历,具体看下文。

int main()
{
    //  创建树
    // **********************************************
    printf("开始...\n");

    MyTree* root = NULL;
    char data[] = {'A', 'B', 'C', 'D', 'E'};
    TreeInit(&root, &data[0]);   // 根结点是 A

    // 在 A 的左边添加 B,返回 B 的位置
    MyTree* nodeB = TreeAddNode(root, (char *)&data[1], LEFT);
    TreeAddNode(nodeB, (char *)&data[3], LEFT);    // 在 B 的左边添加 D
    TreeAddNode(nodeB, (char *)&data[4], RIGHT);	  // 在 B 的右边添加 E
    TreeAddNode(root, (char *)&data[2], RIGHT);    // 在 A 的右边添加 C
    // ***********************************************

    printf("先序遍历:\n");
    PreOrder(root);  // 先序遍历
    printf("\n中序遍历\n");
    InOrder(root);  // 中序遍历
    printf("\n后序遍历\n");
    PostOrder(root);  // 后序遍历

    FreeTree(root);   // 释放树的内存
    printf("\n释放树空间完成。\n");

    return 0;
}

遍历算法

1.先序遍历

// 先序遍历
void PreOrder(MyTree* root) {

    MyStack* head = NULL;
    StackInit(&head);

    MyTree* p = root;

    while (p || !StackEmpty(head)) {

        if (p) {
            TreeNodeVisit(p);
            StackPush(&head, p);
            p = p->lchild;
        }
        else {
            StackPop(&head, (void *)&p);
            p = p->rchild;
        }
    }

    StackFree(head);
}

2.中序遍历

// 中序遍历
void InOrder(MyTree* root) {

    MyStack* head = NULL;
    StackInit(&head);

    MyTree* p = root;

    while (p || !StackEmpty(head)) {

        if (p) {
            StackPush(&head, p);
            p = p->lchild;
        }
        else {
            StackPop(&head, (void *)&p);
            TreeNodeVisit(p);   // 访问结点
            p = p->rchild;
        }
    }
    StackFree(head); // 释放栈
}

3.后序遍历

void PostOrder(MyTree* root) {

    MyStack* head = NULL;
    StackInit(&head);

    MyTree* p = root; // 临时访问指针
    MyTree* recent = NULL;  // 最近一次访问出栈的结点

    while (p || !StackEmpty(head)) {

        if (p) {
            StackPush(&head, p);
            p = p->lchild;  // 一直向左孩子走
        }
        else {
            // 没有左孩子了,就看栈顶结点有没有右孩子
            p = StackTop(head);
            if (p->rchild && p->rchild != recent) {

                p = p->rchild;
                StackPush(&head, p);
                p = p->lchild;
            }
            else {
                // 弹出栈顶的结点
                StackPop(&head, (void *)&p);
                TreeNodeVisit(p);
                recent = p;
                p = NULL; // 标记临时结点 指针 为空(再往后没有子结点了)
            }
        }
    }

    StackFree(head);
}

结果演示

下面运行结果:
在这里插入图片描述
搞定,最后用内存分析工具分析一下我们的程序有没有内存泄露:

 valgrind --tool=memcheck --leak-check=full ./a.out

测试结果,没有内存泄露:
在这里插入图片描述

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
``` #include<stdio.h> #include<stdlib.h> //定义二叉树结构体 struct TreeNode { int data; struct TreeNode *left; struct TreeNode *right; }; //创建节点函数 struct TreeNode *createNode(int data) { struct TreeNode *newNode = (struct TreeNode *)malloc(sizeof(struct TreeNode)); newNode->data = data; newNode->left = NULL; newNode->right = NULL; return newNode; } //插入节点函数 struct TreeNode *insert(struct TreeNode *root, int data) { if (root == NULL) { return createNode(data); } else if (data <= root->data) { root->left = insert(root->left, data); } else { root->right = insert(root->right, data); } return root; } //递归先序遍历函数 void preOrder(struct TreeNode *root) { if (root == NULL) { return; } printf("%d ", root->data); preOrder(root->left); preOrder(root->right); } //递归中序遍历函数 void inOrder(struct TreeNode *root) { if (root == NULL) { return; } inOrder(root->left); printf("%d ", root->data); inOrder(root->right); } //递归后序遍历函数 void postOrder(struct TreeNode *root) { if (root == NULL) { return; } postOrder(root->left); postOrder(root->right); printf("%d ", root->data); } //非递归层次遍历函数 void levelOrder(struct TreeNode *root) { if (root == NULL) { return; } struct TreeNode *queue[100]; int front = 0; int rear = 0; queue[rear] = root; rear++; while (front <= rear) { struct TreeNode *current = queue[front]; front++; printf("%d ", current->data); if (current->left != NULL) { queue[rear] = current->left; rear++; } if (current->right != NULL) { queue[rear] = current->right; rear++; } } } int main() { struct TreeNode *root = NULL; root = insert(root, 5); root = insert(root, 3); root = insert(root, 7); root = insert(root, 2); root = insert(root, 4); root = insert(root, 6); root = insert(root, 8); printf("递归先序遍历:"); preOrder(root); printf("\n"); printf("递归中序遍历:"); inOrder(root); printf("\n"); printf("递归后序遍历:"); postOrder(root); printf("\n"); printf("非递归层次遍历:"); levelOrder(root); printf("\n"); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值