目录
4.二叉树链式结构的操作
4.1 前置说明
4.2二叉树的遍历
4.2.1 前序、中序以及后序遍历
4.3 节点个数以及高度等
4.二叉树链式结构的操作
4.1 前置说明
由于博主对二叉树的结果掌握还不够深入,因此在讲解相关操作前将手动创建一颗简单的二叉树,快速进入正题,等博主二叉树结构了解的差不多时,我将会进行内容补充。
typedef struct TreeNode
{
int data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
TreeNode* CreateNode(int x)
{
TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
node->data = x;
node->left = NULL;
node->right = NULL;
return node;
}
TreeNode* node1 = CreateNode(1);
TreeNode* node2 = CreateNode(2);
TreeNode* node3 = CreateNode(3);
TreeNode* node4 = CreateNode(4);
TreeNode* node5 = CreateNode(5);
TreeNode* node6 = CreateNode(6);
node1->left = node2;
node1->right = node4;
node2->left = node3;
node4->left = node5;
node4->right = node6;
TreeNode* root = node1;
注意:上述代码
并不是创建二叉树的方式
,真正创建二叉树方式后序详解重点讲解。
再看二叉树基本操作前,再回顾下二叉树的概念,
二叉树是:
1.
空树
2.
非空:根节点,根节点的左子树、根节点的右子树组成的。
从概念中可以看出,二叉树定义是
递归式
的,因此后序基本操作中基本都是按照该概念实现的。
4.2二叉树的遍历
4.2.1 前序、中序以及后序遍历
学习二叉树结构,最简单的方式就是遍历。所谓
二叉树遍历
(Traversal)
是按照某种特定的规则,依次对二叉
树中的节点进行相应的操作,并且每个节点只操作一次
。
访问结点所做的操作依赖于具体的应用问题。
遍历
是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。
按照规则,二叉树的遍历有: 前序 / 中序 / 后序的递归结构遍历 :1. 前序遍历 (Preorder Traversal 亦称先序遍历 )—— 访问根结点的操作发生在遍历其左右子树之前。2. 中序遍历 (Inorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之中(间)。3. 后序遍历 (Postorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之后。
由于被访问的结点必是某子树的根,
所以
N(Node
)、
L(Left subtree
)和
R(Right subtree
)又可解释为
根、根的左子树和根的右子树
。
NLR
、
LNR
和
LRN
分别又称为
先根
遍历、
中根
遍历和
后根
遍历。
下面主要分析
前序
递归遍历,中序与后序图解类似,伙伴们可以自己动手绘制。
前序遍历递归图解
:
切记:初次学习一定要画递归展开图便于自己更深入理解递归
下面是实例测试代码(仅供参考):
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef struct TreeNode
{
int data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
TreeNode* CreateNode(int x)
{
TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
node->data = x;
node->left = NULL;
node->right = NULL;
return node;
}
//前序遍历
void PrevOrder(TreeNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
printf("%d ", root->data);
PrevOrder(root->left);
PrevOrder(root->right);
}
//中序遍历
void InOrder(TreeNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
PrevOrder(root->left);
printf("%d ", root->data);
PrevOrder(root->right);
}
//后序遍历
void PostOrder(TreeNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
PrevOrder(root->left);
PrevOrder(root->right);
printf("%d ", root->data);
}
void test01()
{
//创树
TreeNode* node1 = CreateNode(1);
TreeNode* node2 = CreateNode(2);
TreeNode* node3 = CreateNode(3);
TreeNode* node4 = CreateNode(4);
TreeNode* node5 = CreateNode(5);
TreeNode* node6 = CreateNode(6);
node1->left = node2;
node1->right = node4;
node2->left = node3;
node4->left = node5;
node4->right = node6;
TreeNode* root = node1;
//前序遍历
PrevOrder(root);
printf("\n");
//中序遍历
InOrder(root);
printf("\n");
//后序遍历
PostOrder(root);
printf("\n");
}
int main()
{
test01();
return 0;
}
4.3 节点个数以及高度等
1..计算高度:
//方法一
int TreeHeight(TreeNode* root)
{
return TreeHeight(root->left) > TreeHeight(root->right) ?
TreeHeight(root->left) + 1 :
TreeHeight(root->right) + 1;
}
//方法二
int TreeHeight(TreeNode* root)
{
if (root == NULL)
return 0;
int left = TreeHeight(root->left);
int right = TreeHeight(root->right);
return left > right ? left + 1 : right + 1;
}
由于方法一中比较时就开始递归了,却没有记录数据,导致后一条语句又要进行递归遍历,非常耗时间,因此用第二种方法更好
2.计算总结点个数:
int TreeSize(TreeNode* root)
{
return root == NULL ? 0 :
TreeSize(root->left) +
TreeSize(root->right) + 1;
}
此为三目操作符的运用
3.计算第k层的节点个数:
int TreeKSize(TreeNode* root,int k)
{
assert(k > 0);
if (root == NULL)
return 0;
if (k == 1)
return 1;
return TreeKSize(root->left, k - 1)
+ TreeKSize(root->right, k - 1);
}
4.叶节点个数:
int TreeLeafSize(TreeNode* root)
{
if (root == NULL)
return 0;
if (root->left == NULL
&& root->right == NULL)
return 1;
return TreeLeafSize(root->left) +
TreeLeafSize(root->right);
}