二叉树的递归遍历
-
先序遍历
- 先跟
- 再左
- 再右
-
中序遍历
- 先左
- 再根
- 再右
-
后序遍历
- 先左
- 再右
- 再根
-
需要遍历的树
-
先序遍历结果:
A B C D E F G H
-
中序遍历结果:
B D C E A F H G
-
后续遍历结果:
D E C B H G F A
递归遍历实现代码
// 二叉树节点
struct BinaryNode
{
char* ch;// 显示的字母
struct BinaryNode* lChild; // 左孩子
struct BinaryNode* rChild; // 右孩子
};
// 递归函数 实现遍历
void recursion(struct BinaryNode* root)
{
if (root == NULL)
{
return;
}
// 根
printf("%c\n", root->ch);
// 左
recursion(root->lChild);
// 右
recursion(root->rChild);
}
void test01()
{
// 创建节点
struct BinaryNode nodeA = { 'A', NULL, NULL };
struct BinaryNode nodeB = { 'B', NULL, NULL };
struct BinaryNode nodeC = { 'C', NULL, NULL };
struct BinaryNode nodeD = { 'D', NULL, NULL };
struct BinaryNode nodeE = { 'E', NULL, NULL };
struct BinaryNode nodeF = { 'F', NULL, NULL };
struct BinaryNode nodeG = { 'G', NULL, NULL };
struct BinaryNode nodeH = { 'H', NULL, NULL };
// 建立节点之间的关系
nodeA.lChild = &nodeB;
nodeA.rChild = &nodeF;
nodeB.lChild = NULL;
nodeB.rChild = &nodeC;
nodeC.lChild = &nodeD;
nodeC.rChild = &nodeE;
nodeF.lChild = NULL;
nodeF.rChild = &nodeG;
nodeG.lChild = &nodeH;
nodeG.rChild = NULL;
// 通过递归函数实现先序遍历
recursion(&nodeA);
}
二叉树的常规编程
求二叉树叶子数量
- 利用递归特性统计
- 节点左子树 和 右子树 同时是NULL, 认定为叶子
代码实现
void calculateLeafNum(struct BinaryNode* root, int* num)
{
if (root == NULL)
{
return;
}
if (root->lChild == NULL && root->rChild == NULL)
{
(*num)++;
return;
}
calculateLeafNum(root->lChild, num);
calculateLeafNum(root->rChild, num);
}
求二叉树的高度
- 利用递归特性统计
- 左子树 和 右子树高度相比 取大的值 +1 就是树的高度
代码实现
// 统计树的高度
int getTreeHeight(struct BinaryNode* root)
{
if (root == NULL)
{
return 0;
}
// 获取左子树的高度
int lHeight = getTreeHeight(root->lChild);
// 获取右子树的高度
int rHeight = getTreeHeight(root->rChild);
// 取大的值+ 1 就是树的高度
int height = lHeight > rHeight ? lHeight + 1 : rHeight + 1;
return height;
}
拷贝二叉树
- 利用递归特性
- 先拷贝左子树
- 再拷贝右子树
- 创建新节点
- 将左子树 右子树 挂在新节点上
- 返回新节点
实现代码
// 拷贝二叉树
struct BinaryNode* copyTree(struct BinaryNode* root)
{
if (root == NULL)
{
return NULL;
}
// 先拷贝左子树
struct BinaryNode* lChild = copyTree(root->lChild);
// 再拷贝右子树
struct BinaryNode* rChild = copyTree(root->rChild);
// 创建新节点
struct BinaryNode* newNode = malloc(sizeof(struct BinaryNode));
newNode->lChild = lChild;
newNode->rChild = rChild;
newNode->ch = root->ch;
// 返回结果
return newNode;
}
释放二叉树
- 利用递归特性
- 先释放左子树
- 再释放右子树
- 再释放根节点
实现代码
// 释放新树
void freeTree(struct BinaryNode* root)
{
if (root == NULL)
{
return;
}
// 先释放左子树
freeTree(root->lChild);
// 再释放右子树
freeTree(root->rChild);
printf("%c 被释放了\n", root->ch);
// 最后释放根节点
free(root);
}
二叉树的非递归遍历
- 将根节点压入栈中
- 进入循环: 只要栈中元素大于0, 进行循环操作
- 弹出栈顶元素
- 如果这个栈元素为真
- 输出这个元素, 且执行下一次循环
- 如果栈顶元素为假
- 将节点的标志设为真
- 将该节点的右子树, 左子树, 根 压入栈中
- 执行下一次循环
设计
- 将每个节点元素多加一个标志位, 默认标志位都为假
struct BinaryNode
{
char* ch;// 显示的字母
struct BinaryNode* lChild; // 左孩子
struct BinaryNode* rChild; // 右孩子
int flag; // 节点标志
};
代码实现
// 非递归遍历
void nonRecursion(struct BinaryNode* root)
{
// 创建栈
SeqStack myStack = init_SeqStack();
// 将根节点压入栈中
push_SeqStack(myStack, root);
// 只要栈中元素大于0, 进行循环操作
while (size_SeqStack(myStack) > 0)
{
// 获取栈顶元素
struct BinaryNode* topNode = top_SeqStack(myStack);
// 弹出栈顶元素
pop_SeqStack(myStack);
if (topNode->flag == 1)
{
// 栈元素为真
// 输出这个元素
printf("%c\n", topNode->ch);
// 执行下一次循环
continue;
}
// 如果栈顶元素为假
// 将节点的标志设为真
topNode->flag = 1;
// 将该节点的右子树, 左子树, 根 压入栈中
if (topNode->rChild != NULL)
{
push_SeqStack(myStack, topNode->rChild);
}
if (topNode->lChild != NULL)
{
push_SeqStack(myStack, topNode->lChild);
}
push_SeqStack(myStack,topNode);
}
// 销毁栈
destroy_SeqStack(myStack);
}