个人主页:为梦而生~ 关注我一起学习吧!
⭐️往期关于树的文章:
【哈夫曼树】基本概念、构建过程及C++代码
【线索二叉树】C++代码及线索化过程详解
欢迎阅读!
根据二叉树先序和中序遍历的结果,生成该二叉树。并输出后序、层序遍历结果。
本设计使用的是广度优先搜索算法,并且需要输出路径,所以用到了栈和队列。详细设计方案如下:
//定义树的存储结构
typedef struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
}*BiTree;
//定义链表的存储结构
typedef struct Node {
TreeNode* data;
struct Node* next;
}Node, *QueueNode;
//定义队列的存储结构
typedef struct Queue{
Node* front, * rear;
}*LinkQueue;
int pre[MAXSIZE], in[MAXSIZE], post[MAXSIZE]; // 定义全局数组,存放遍历结果
int idx[MAXSIZE]; // 记下每个节点在中序遍历结果中的下标位置
int leaves[MAXSIZE]; // 存放所有叶子节点
int post_idx = 0; // 定义全局变量,记录后序遍历的当前位置
int leaf_idx = 0; // 定义全局变量,记录叶子节点的个数
LinkQueue level_queue = (Queue*)malloc(sizeof(Queue)); //创建用于层序遍历的队列
int n;
printf("请输入节点个数:");
scanf("%d", &n);
printf("请输入二叉树前序遍历结果:");
for (int i = 0; i < n; i++) {
scanf("%d", &pre[i]);
}
printf("请输入二叉树中序遍历结果:");
for (int i = 0; i < n; i++) {
scanf("%d", &in[i]);
idx[in[i]] = i;
}
// 根据前序和中序遍历结果构建二叉树
BiTree buildTree(int pre_left, int pre_right, int in_left, int in_right) {
//根据边界判断是否到叶子结点
if (pre_left > pre_right) {
return NULL;
}
int root_val = pre[pre_left]; //结点的值为当前前序遍历当前的值
int in_idx = idx[root_val]; //找到中序遍历该结点对应的下标
TreeNode* root = createNode(root_val); //创建新的结点
root->left = buildTree(pre_left + 1, pre_left + (in_idx - in_left), in_left, in_idx - 1); //递归生成左子树
root->right = buildTree(pre_left + (in_idx - in_left) + 1, pre_right, in_idx + 1, in_right);//递归生成右子树
return root; //返回根结点指针
}
// 递归遍历二叉树,生成后序遍历结果
void generate_postorder(BiTree root) {
if (root == NULL) {
return;
}
generate_postorder(root->left); //递归遍历左字数
generate_postorder(root->right);//递归遍历右子树
post[post_idx++] = root->val; //输出当前结点值
}
void level_traversal(BiTree root, LinkQueue queue) {
if (root == NULL) {
return;
}
// 根结点入队
enQueue(queue, root);
// 队列不空时遍历
while(queue->front != NULL){
TreeNode* p = (TreeNode*)malloc(sizeof(TreeNode));
deQueue(queue, &p); // 出队
printf("%d ", p->val); // 输出
if(root->left != NULL){
enQueue(queue, p->left); //若左子树不为空,将左子树根节点入队
}
if(root->right != NULL){
enQueue(queue, p->right); //若右子树不为空,将右子树根节点入队
}
}
}
代码实现:
#define _CRT_SECURE_NO_WARNINGS //在VS中使用 避免出现scanf printf不安全的警告
#include
#include
#define MAXSIZE 100 // 定义最大结点数量
//定义树的存储结构
typedef struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
}*BiTree;
//定义链表的存储结构
typedef struct Node {
TreeNode* data;
struct Node* next;
}Node, *QueueNode;
//定义队列的存储结构
typedef struct Queue{
Node* front, * rear;
}*LinkQueue;
int pre[MAXSIZE], in[MAXSIZE], post[MAXSIZE]; // 定义全局数组,存放遍历结果
int idx[MAXSIZE]; // 记下每个节点在中序遍历结果中的下标位置
int leaves[MAXSIZE]; // 存放所有叶子节点
int post_idx = 0; // 定义全局变量,记录后序遍历的当前位置
int leaf_idx = 0; // 定义全局变量,记录叶子节点的个数
// 创建新节点
BiTree createNode(int val) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(struct TreeNode));
newNode->val = val;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
// 根据前序和中序遍历结果构建二叉树
BiTree buildTree(int pre_left, int pre_right, int in_left, int in_right) {
//根据边界判断是否到叶子结点
if (pre_left > pre_right) {
return NULL;
}
int root_val = pre[pre_left]; //结点的值为当前前序遍历当前的值
int in_idx = idx[root_val]; //找到中序遍历该结点对应的下标
TreeNode* root = createNode(root_val); //创建新的结点
root->left = buildTree(pre_left + 1, pre_left + (in_idx - in_left), in_left, in_idx - 1); //递归生成左子树
root->right = buildTree(pre_left + (in_idx - in_left) + 1, pre_right, in_idx + 1, in_right);//递归生成右子树
return root; //返回根结点指针
}
// 递归遍历二叉树,生成后序遍历结果
void generate_postorder(BiTree root) {
if (root == NULL) {
return;
}
generate_postorder(root->left); //递归遍历左字数
generate_postorder(root->right);//递归遍历右子树
post[post_idx++] = root->val; //输出当前结点值
}
// 初始化队列
void initQueue(LinkQueue queue) {
queue->front = NULL;
queue->rear = NULL;
}
// 入队操作
void enQueue(LinkQueue queue, TreeNode* val) {
QueueNode node = (QueueNode) malloc(sizeof(Node));
node->data = val;
node->next = NULL;
if (queue->rear == NULL) {
queue->front = node;
queue->rear = node;
} else {
queue->rear->next = node;
queue->rear = node;
}
}
// 出队操作
void deQueue(LinkQueue queue, BiTree* val) {
if (queue->front == NULL) {
printf("Error: queue is empty!\n");
exit(1);
}
*val = queue->front->data;
QueueNode temp = queue->front;
queue->front = queue->front->next;
if (queue->front == NULL) {
queue->rear = NULL;
}
free(temp);
}
// 层序遍历二叉树
void level_traversal(BiTree root, LinkQueue queue) {
if (root == NULL) {
return;
}
// 根结点入队
enQueue(queue, root);
// 队列不空时遍历
while(queue->front != NULL){
TreeNode* p = (TreeNode*)malloc(sizeof(TreeNode));
deQueue(queue, &p); // 出队
printf("%d ", p->val); // 输出
if(root->left != NULL){
enQueue(queue, p->left); //若左子树不为空,将左子树根节点入队
}
if(root->right != NULL){
enQueue(queue, p->right); //若右子树不为空,将右子树根节点入队
}
}
}
// 找出所有叶子节点
void find_leaves(BiTree root) {
if (root == NULL) {
return;
}
if (root->left == NULL && root->right == NULL) {
leaves[leaf_idx++] = root->val;
}
find_leaves(root->left);
find_leaves(root->right);
}
int main() {
LinkQueue level_queue = (Queue*)malloc(sizeof(Queue)); //创建用于层序遍历的队列
int n;
printf("请输入节点个数:");
scanf("%d", &n);
printf("请输入二叉树前序遍历结果:");
for (int i = 0; i < n; i++) {
scanf("%d", &pre[i]);
}
printf("请输入二叉树中序遍历结果:");
for (int i = 0; i < n; i++) {
scanf("%d", &in[i]);
idx[in[i]] = i;
}
BiTree root = buildTree(0, n - 1, 0, n - 1);
generate_postorder(root);
find_leaves(root);
printf("后序遍历结果为:");
for (int i = 0; i < n; i++) {
printf("%d ", post[i]);
}
printf("\n");
printf("层序遍历结果为:");
initQueue(level_queue);
level_traversal(root, level_queue);
printf("\n");
printf("所有叶子节点为:");
for (int i = 0; i < leaf_idx; i++) {
printf("%d ", leaves[i]);
}
printf("\n");
return 0;
}