使用层次序列构建二叉树(C语言实现)

在数据结构学习过程中,二叉树的构建方式通常有递归建树(前序/中序)和 层次建树(广度优先)两种。本文将介绍一种基于辅助队列实现的层次建树方法 ,并结合前序、中序、后序遍历结果来验证构建的正确性。
🌳 示例结构
输入层次序列:a b c d e f g
预期构建出的二叉树结构如下:
a
/ \
b c
/ \ / \
d e f g
🧠 思路解析
层次建树的关键是 广度优先遍历的顺序插入节点。为了实现这一目标,我们需要:
- 使用一个结构体指针队列,保存待填左右孩子的节点。
- 每读入一个字符,就创建一个新树节点,并尝试插入到当前队首节点的左或右孩子位置。
- 如果左右孩子都已填满,就将当前队首出队,指向下一个节点。
🛠️ 关键数据结构
c
// 树节点结构体
typedef struct BiTNode {
char data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
// 辅助队列节点(保存 BiTree 指针)
typedef struct tag {
BiTNode *p;
struct tag *pnext;
} tag_t, *ptag_t;
🧩 核心建树逻辑
c
BiTree tree = NULL; // 根节点
ptag_t phead = NULL, ptail = NULL, listpnew = NULL, pre = NULL;
char c;
while(scanf("%c", &c)) {
if(c == '\n') break;
BiTree pnew = (BiTree)calloc(1, sizeof(BiTNode));
pnew->data = c;
listpnew = (ptag_t)calloc(1, sizeof(tag_t));
listpnew->p = pnew;
if(tree == NULL) {
tree = pnew;
phead = ptail = listpnew;
pre = listpnew;
} else {
ptail->pnext = listpnew;
ptail = listpnew;
if(pre->p->lchild == NULL) {
pre->p->lchild = pnew;
} else if(pre->p->rchild == NULL) {
pre->p->rchild = pnew;
pre = pre->pnext; // 移动到下一个节点
}
}
}
🔁 遍历验证
前序遍历(PreOrder):
c
void PreOrder(BiTree p) {
if(p != NULL) {
printf("%c", p->data);
PreOrder(p->lchild);
PreOrder(p->rchild);
}
}
中序遍历(InOrder):

c
void InOrder(BiTree p) {
if(p != NULL) {
InOrder(p->lchild);
printf("%c", p->data);
InOrder(p->rchild);
}
}
后序遍历(PostOrder):
c
void PostOrder(BiTree p) {
if(p != NULL) {
PostOrder(p->lchild);
PostOrder(p->rchild);
printf("%c", p->data);
}
}
完整代码
c
//层次建树 借助一个辅助队列
// a
// b c
// d e f g
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
//借助辅助队列来进行建树
typedef struct LinkNode{
char datac; //数据结点
}LinkNode; //建立一个结点
//这里没有使用标准的链队列来实现 相应的层次建树
typedef struct {
LinkNode *front, *rear;
}LinkQueue; //建立队列#
建立数的结点 使用的是链式的存储
typedef struct BiTNode{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode , * BiTree;
//而是建立一个辅助队列 tag
typedef struct tag{
// BiTree p; //树的某一结点的地址值
BiTNode *p;
struct tag *pnext;
}tag_t , *ptag_t;
//前序遍历
void PreOrder(BiTree p){
if(p!=NULL){
printf("%c",p->data);
PreOrder(p->lchild);
PreOrder(p->rchild);
}
}
//中序遍历
void InOrder(BiTree p){
if(p!=NULL){
InOrder(p->lchild);
printf("%c",p->data);
InOrder(p->rchild);
}
}
//后序遍历
void PostOrder(BiTree p){
if(p!=NULL){
PostOrder(p->lchild);
PostOrder(p->rchild);
printf("%c",p->data);
}
}
int main() {
BiTree pnew; //用来指向新申请的数结点
BiTree tree =NULL; //tree 是指向树根的,代表树
ptag_t phead= NULL,ptail =NULL, listpnew =NULL, pre =NULL; //初始化队列 定义一个pre 指向执行的当前元素
char c;
//abcdef
while(scanf("%c",&c)){
if(c=='\n'){
break;
}
//calloc申请空间 大小是两个参数相乘,并对空间进行初始化 赋值为0;
//malloc 申请以后还需要对其进行赋值 malloc 返回的是 void * 类型的 也需要进行强制转换
树申请结点
pnew =(BiTree) calloc(1,sizeof(BiTNode));
pnew->data = c;
//队列结点申请空间
listpnew = (ptag_t) calloc(1,sizeof(tag_t)); //申请一个结构体类型的结点 返回一个指针类型的
listpnew->p =pnew;
//如果是数的第一个结点
if(tree==NULL){
tree = pnew; //tree 指向根的头结点
//第一个结点 即是队列头也是 队列尾
phead = ptail = listpnew;
pre = listpnew; // 用来判断当前结点 的左右孩子是否满了
}else {
//元素直接入队
ptail ->pnext = listpnew;
ptail =listpnew;
//接下来把元素放入树中
if(pre->p->lchild ==NULL){
pre ->p ->lchild =pnew; // pre -> p 左孩子为空 就放入左孩子
}else if(pre->p->rchild==NULL){
pre->p->rchild =pnew;
pre = pre->pnext; // !!! 左右孩子都满了,指向下一个节点
}
}
}
PreOrder(tree);
printf("\n");
InOrder(tree);
printf("\n");
PostOrder(tree);
return 0;
//这没有对树进行相应的输出 ,使用调试发现建树完成
}
//D:\TextOPT\C_CPP_code\For408\DateS\5\SqBinaryTree1\cmake-build-debug\SqBinaryTree1.exe
//123456789
//124895367
//849251637
//894526731
📌 完整输出样例
以输入:abcdefg
(按层次顺序输入,以回车结束)为例:
输入:
abcdefg↵
输出:
前序遍历:abdecfg
中序遍历:dbeafcg
后序遍历:debgfca
输出对应的树结构:
a
/ \
b c
/ \ / \
d e f g

✅ 总结
- 使用辅助队列可以按层次方式构建二叉树,代码逻辑清晰,效率也较高。
- 在建树过程中,记得及时更新队列指针(例如
pre = pre->pnext;
)以避免插入错误。 - 可结合三种遍历结果验证建树的正确性。