如何由中序遍历和后序遍历推出前序遍历?
1.由后续遍历确定头结点。
2.根据头结点在中序遍历中的位置划分出左右子树
3.循环上诉两步画出完整二叉树。
4.由二叉树写成前序遍历
BinaryTree.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include"Queue.h"
typedef int BTDataType;
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* left;//存储左子树的地址
struct BinaryTreeNode* right;//存储右子树的地址
BTDataType data;//存储数据
}BTNode;
BTNode* BuyNode(BTDataType x);//创建节点函数
void PreOrder(BTNode* root);//前序遍历
void InOrder(BTNode* root);//中序遍历
void PostOrder(BTNode* root);//后序遍历
int TreeSize(BTNode* root);//计算节点个数
int TreeLeafSize(BTNode* root);//计算叶子节点个数
int TreeKLevel(BTNode* root, int k);//计算第k层的节点个数
int TreeDepth(BTNode* root);//求二叉树的深度(高度)
BTNode* TreeFind(BTNode* root, BTDataType x);//查找二叉树中为x的结点
void TreeDestroy(BTNode* root);//销毁函数
void LevelOrder(BTNode* root);//二叉树的层序遍历
bool TreeComplete(BTNode* root);//判断一颗树是否是完全二叉树
BinaryTree.c
#include "BinaryTree.h"
BTNode* BuyNode(BTDataType x)//创建节点函数
{
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
assert(newnode);//malloc开辟空间有可能失败需要检查
newnode->left = NULL;
newnode->right = NULL;
newnode->data = x;
return newnode;
}
void PreOrder(BTNode* root)//前序遍历
{
if (root == NULL)//遇到空时打印 #
{
printf("# ");
return;
}
printf("%d ", root->data);//打印根
PreOrder(root->left);//访问左子树
PreOrder(root->right);//访问右子树
}
void InOrder(BTNode* root)//中序遍历
{
if (root == NULL)//遇到空时打印 #
{
printf("# ");
return;
}
InOrder(root->left);//访问左子树
printf("%d ", root->data);//打印根
InOrder(root->right);//访问右子树
}
void PostOrder(BTNode* root)//后序遍历
{
if (root == NULL)//遇到空时打印 #
{
printf("# ");
return;
}
PostOrder(root->left);//访问左子树
PostOrder(root->right);//访问右子树
printf("%d ", root->data);//打印根
}
int TreeSize(BTNode* root)//计算节点个数
{
return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;//经典的后序遍历
}
int TreeLeafSize(BTNode* root)//计算叶子节点个数
{
if (root == NULL) //递归一定要设置结束条件
return 0;
if (root->left == NULL && root->right == NULL)//当左右子树都为空时,当前结点才为叶子节点。
return 1;
return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
int TreeKLevel(BTNode* root, int k)//计算第k层的节点个数
{
assert(k >= 1);//一定要检查传入K的范围。
if (root == NULL) //递归一定要设置结束条件
return 0;
if (k == 1)
return 1;
return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}
int TreeDepth(BTNode* root)//求二叉树的深度(高度)
{
if (root == NULL) //递归一定要设置结束条件
return 0;
int leftDepth = TreeDepth(root->left);
int rightDepth = TreeDepth(root->right);
return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
BTNode* TreeFind(BTNode* root, BTDataType x)//查找二叉树中第一个为x的结点
{
if (root == NULL)
return NULL;
if (root->data == x)
return root;
//return TreeFind(root->left, x) || TreeFind(root->right, x);//不能这样写,NULL也会被返回
BTNode* ret1 = TreeFind(root->left, x);
if (ret1)
return ret1;
BTNode* ret2 = TreeFind(root->right, x);
if (ret2)
return ret2;
return NULL;
}
void TreeDestroy(BTNode* root)//销毁函数
{
if (root == NULL)
return;
TreeDestroy(root->left);
TreeDestroy(root->right);
free(root);//销毁左右子树后,再销毁根节点(经典后序)
}
void LevelOrder(BTNode* root)//二叉树的层序遍历
{
Queue q;//创建一个队列
QueueInit(&q);//初始化队列
if (root)
QueuePush(&q, root);//如果节点不为空,节点入队
while (!QueueEmpty(&q))//如果队列不为空,继续遍历
{
BTNode* front = QueueFront(&q);//取出队头节点
printf("%d ", front->data);//打印
QueuePop(&q);//出队列
if(front->left)
QueuePush(&q, front->left);//如果左孩子节点不为空,左孩子节点入队
if (front->right)
QueuePush(&q, front->right);//如果右孩子节点不为空,右孩子节点入队
}
putchar(10);//换行
QueueDestroy(&q);//使用完后一定要记得销毁队列。
}
bool TreeComplete(BTNode* root)//判断一颗树是否是完全二叉树
{
Queue q;//创建一个队列
QueueInit(&q);//初始化队列
if (root)
QueuePush(&q, root);//如果节点不为空,节点入队
while (!QueueEmpty(&q))//如果队列不为空,继续遍历
{
BTNode* front = QueueFront(&q);//取出队头节点
QueuePop(&q);//出队列 (Pop的是链式队列的结点,和结点里的内容(二叉树的节点)无关)
if (front == NULL)//遇到NULL,跳出循环
break;
else
{
QueuePush(&q, front->left);//无论左孩子节点为不为空,左孩子节点入队
QueuePush(&q, front->right);//无论右孩子节点为不为空,右孩子节点入队
}
}
//如果队列不为空,且队列中的所有元素全为空,则是完全二叉树
while (!QueueEmpty(&q))//如果队列不为空,继续遍历
{
BTNode* front = QueueFront(&q);//取出队头节点
QueuePop(&q);//出队列
if (front)//如果在空后遇到非空
{
QueueDestroy(&q);//销毁队列
return false;
}
}
//如果顺利队列清空,说明在层序遍历中没有遇到 NULL 后还有 非NULL 的情况,证明该树是完全二叉树。
QueueDestroy(&q);//使用完后一定要记得销毁队列。
return true;
}
BinaryTreeTest.c(测试用例)
测试用例里构建的二叉树:
#include"BinaryTree.h"
int main()
{
//建立一颗二叉树。
BTNode* root = BuyNode(1);
BTNode* n2 = BuyNode(2);
BTNode* n3 = BuyNode(3);
BTNode* n4 = BuyNode(4);
BTNode* n5 = BuyNode(5);
BTNode* n6 = BuyNode(6);
BTNode* n7 = BuyNode(7);
root->left = n2;
root->right = n4;
n2->left = n3;
n2->right = n7;
n4->left = n5;
n4->right = n6;
//前序遍历
printf("前序遍历:");
PreOrder(root);
putchar(10);
//中序遍历
printf("中序遍历:");
InOrder(root);
putchar(10);
//后序遍历
printf("后序遍历:");
PostOrder(root);
putchar(10);
//计算节点个数
printf("该树有%d个节点。\n",TreeSize(root));
//计算叶子节点个数
printf("该树有%d个叶子节点。\n", TreeLeafSize(root));
//求二叉树的深度(高度)
printf("该树的高度为(设根节点的高度为1):%d\n", TreeDepth(root));
//计算第k层的节点个数
printf("你想要计算第几层的节点:");
int k = 0;
scanf("%d", &k);
printf("该树第%d层有%d个节点。\n", k, TreeKLevel(root, k));
//查找二叉树中第一个为x的结点
printf("你想要查找二叉树中的哪个节点,请输入节点存储的值:");
int x = 0;
scanf("%d", &x);
BTNode* f = TreeFind(root, x);
if (f != NULL)
printf("二叉树中第一个为%d的节点的地址为:%p。\n", f->data, f);
else
printf("未找到该节点\n");
//二叉树的层序遍历
printf("层序遍历:");
LevelOrder(root);
//判断一棵树是否是完全二叉树。
if(TreeComplete(root))
printf("该树是一颗完全二叉树\n");
else
printf("该树不是一颗完全二叉树\n");
//销毁函数
TreeDestroy(root);
return 0;
}
结果展示: