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

一、几个概念

二叉树(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;
}
相关推荐
懒惰才能让科技进步16 分钟前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝
Ni-Guvara30 分钟前
函数对象笔记
c++·算法
泉崎1 小时前
11.7比赛总结
数据结构·算法
你好helloworld1 小时前
滑动窗口最大值
数据结构·算法·leetcode
AI街潜水的八角2 小时前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
白榆maple2 小时前
(蓝桥杯C/C++)——基础算法(下)
算法
JSU_曾是此间年少2 小时前
数据结构——线性表与链表
数据结构·c++·算法
sjsjs112 小时前
【数据结构-合法括号字符串】【hard】【拼多多面试题】力扣32. 最长有效括号
数据结构·leetcode
此生只爱蛋3 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
blammmp3 小时前
Java:数据结构-枚举
java·开发语言·数据结构