扩展二叉树前序遍历序列构建二叉树(图解)

一、几个概念

二叉树(binary tree):是 n(n >= 0)个结点(每个结点最多只有2棵子树)的有限集合,该集合可为空集(称为空二叉树),或由一个根节点和两颗互不相交的,称为根节点的左子树和右子树的二叉树组成。

扩展二叉树:将二叉树中的每个结点的空子结点用一个虚拟结点表示,其值为一特定的值,比如"#",这样每个结点都有两个子结点,这种处理后的二叉树为原二叉树的扩展树。扩展二叉树就可以做到一个遍历序列确定一颗二叉树。

例如:图1为一颗二叉树,图2为这颗二叉树的扩展二叉树

前序遍历二叉树 :先访问根结点,然后遍历左子树,最后遍历右子树

所以,图1这颗二叉树的前序遍历顺序为:ABDEGCF

这颗二叉树的扩展二叉树前序遍历序列为:ABD##E#G##CF###

二叉链表:是二叉树的一种链式存储结构,其中每个结点包含三个字段:一个数据字段(data)和两个指针字段(lchild、rchild),分别指向该结点的左孩子和右孩子。如果某个结点没有左孩子或右孩子,那么对应的指针字段为NULL。

用 C 语言可以表述为:

cpp 复制代码
typedef struct binary_node {
    char data;
    struct binary_node *lchild, *rchild;
}binary_tree;

二、算法思路

扩展二叉树前序遍历序列创建二叉树过程:

(1)如果该结点为虚拟结点(即值 = '#'),则该结点为空

(2)如果该结点存在,则创建该结点,并把值赋给 data 字段,然后创建左子树,最后创建右子树

所以,这是一个递归的过程。

那么对于图2的扩展二叉树前序遍历序列:ABD##E#G##CF###

调用创建二叉树函数图解整个创建二叉树过程为:

(1)调用创建二叉树函数,因为根结点的值为A,则创建该节点,并赋值该节点的 data = 'A'

(2)调用创建二叉树函数创建A结点的左子树,因为该结点的值为B,则创建该结点,并赋值该结点的 data = 'B'

(3)调用创建二叉树函数创建B结点的左子树,因为该结点的值为D,则创建该结点,并赋值该结点的 data = 'D'

(4)调用创建二叉树函数创建D结点的左子树,因为该结点的值为#,则该结点为空,并赋值 lchild = NULL,然后,栈顶的 create_binary_tree 函数执行完毕,从栈顶弹出

(5)调用创建二叉树函数创建D结点的右子树,因为该结点的值为#,则该结点为空,并赋值 rchild = NULL,然后,栈顶的 create_binary_tree 函数执行完毕,从栈顶弹出

(6)此时创建结点D的 create_binary_tree 函数访问结点D和创建D结点的左子树、右子树逻辑都已执行完毕,从栈顶弹出,然后,执行调用 create_binary_tree 函数创建结点B的右子树,因为该结点的值为E,则创建该结点,并赋值该结点的 data = 'E'

(7)调用创建二叉树函数创建E结点的左子树,因为该结点的值为#,则该结点为空,并赋值 lchild = NULL,然后,栈顶的 create_binary_tree 函数执行完毕,从栈顶弹出

(8)调用创建二叉树函数创建E结点的右子树,因为该结点的值为G,则创建该结点,并赋值该结点的 data = 'G'

(9)调用创建二叉树函数创建G结点的左子树,因为该结点的值为#,则该结点为空,并赋值 lchild = NULL,然后,栈顶的 create_binary_tree 函数执行完毕,从栈顶弹出

(10)调用创建二叉树函数创建G结点的右子树,因为该结点的值为#,则该结点为空,并赋值 rchild = NULL,然后,栈顶的 create_binary_tree 函数执行完毕,从栈顶弹出

(11)此时创建结点G的 create_binary_tree 函数访问结点G和创建G结点的左子树、右子树逻辑都已执行完毕,从栈顶弹出。

(12)此时创建结点E的 create_binary_tree 函数访问结点E和创建E结点的左子树、右子树逻辑都已执行完毕,从栈顶弹出。

(13)此时创建结点B的 create_binary_tree 函数访问结点B和创建B结点的左子树、右子树逻辑都已执行完毕,从栈顶弹出。

(14)调用创建二叉树函数创建A结点的右子树,因为该结点的值为C,则创建该结点,并赋值该结点的 data = 'C'

(15)调用创建二叉树函数创建C结点的左子树,因为该结点的值为F,则创建该结点,并赋值该结点的 data = 'F'

(16)调用创建二叉树函数创建F结点的左子树,因为该结点的值为#,则该结点为空,并赋值 lchild = NULL,然后,栈顶的 create_binary_tree 函数执行完毕,从栈顶弹出

(16)调用创建二叉树函数创建F结点的右子树,因为该结点的值为#,则该结点为空,并赋值 rchild = NULL,然后,栈顶的 create_binary_tree 函数执行完毕,从栈顶弹出

(17)此时创建结点F的 create_binary_tree 函数访问结点F和创建F结点的左子树、右子树逻辑都已执行完毕,从栈顶弹出。

(18)调用创建二叉树函数创建C结点的右子树,因为该结点的值为#,则该结点为空,并赋值 rchild = NULL,然后,栈顶的 create_binary_tree 函数执行完毕,从栈顶弹出

(19)此时创建结点C的 create_binary_tree 函数访问结点C和创建C结点的左子树、右子树逻辑都已执行完毕,从栈顶弹出。

(20)此时创建结点A的 create_binary_tree 函数访问结点A和创建A结点的左子树、右子树逻辑都已执行完毕,从栈顶弹出。至此,调用 create_binary_tree 函数创建二叉树函数逻辑都已执行完毕,整个函数返回,我们成功的用二叉树的扩展二叉树前序遍历序列构建二叉树如下所示

三、实现代码

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct binary_node {
    char data;
    struct binary_node *lchild, *rchild;
}binary_tree;

//前序遍历扩展二叉树
char *g_str = "ABD##E#G##CF###";
int g_index = 0;

void create_binary_tree(binary_tree **T) {
    if (strlen(g_str) == 0)
        return;

    if (g_str[g_index] == '#') {
        T = NULL;
        ++g_index;
    }
    else {
        *T = malloc(sizeof(**T));
        (*T)->data = g_str[g_index];
        (*T)->lchild = NULL;
        (*T)->rchild = NULL;
        ++g_index;

        create_binary_tree(&(*T)->lchild);
        create_binary_tree(&(*T)->rchild);
    }
}

void visit_node(binary_tree *T) {
    printf("%c\n", T->data);
}

void pre_order_tree(binary_tree *T) {
    if (!T)
        return;

    visit_node(T);
    pre_order_tree(T->lchild);
    pre_order_tree(T->rchild);
}

int main(int argc, char *argv[]) {
    binary_tree *T = NULL;
    create_binary_tree(&T);
    pre_order_tree(T);

    return 0;
}
相关推荐
许野平22 分钟前
Rust: enum 和 i32 的区别和互换
python·算法·rust·enum·i32
chenziang129 分钟前
leetcode hot100 合并区间
算法
chenziang130 分钟前
leetcode hot100 对称二叉树
算法·leetcode·职场和发展
szuzhan.gy1 小时前
DS查找—二叉树平衡因子
数据结构·c++·算法
一只码代码的章鱼2 小时前
排序算法 (插入,选择,冒泡,希尔,快速,归并,堆排序)
数据结构·算法·排序算法
青い月の魔女2 小时前
数据结构初阶---二叉树
c语言·数据结构·笔记·学习·算法
我要出家当道士2 小时前
Nginx单向链表 ngx_list_t
数据结构·nginx·链表·c
林的快手3 小时前
209.长度最小的子数组
java·数据结构·数据库·python·算法·leetcode
千天夜3 小时前
多源多点路径规划:基于启发式动态生成树算法的实现
算法·机器学习·动态规划
从以前3 小时前
准备考试:解决大学入学考试问题
数据结构·python·算法