一、构建二叉树
//构造一个二叉树的结点
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
int val;
}BTNode;
BTNode* BuyNode(int val)
{
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
if (newnode == NULL)
{
printf("malloc fail");
exit(-1);
}
newnode->left = NULL;
newnode->right = NULL;
newnode->val = val;
return newnode;
}
这里使用结构体来表示二叉树的一个结点,结点的参数包括左右指针和值。然后构造了一个BuyNode函数,用来为申请的二叉树结点开辟空间。
二、主函数的实现
int main()
{
BTNode* node1 = BuyNode(1);
BTNode* node2 = BuyNode(2);
BTNode* node3 = BuyNode(3);
BTNode* node4 = BuyNode(4);
BTNode* node5 = BuyNode(5);
BTNode* node6 = BuyNode(6);
BTNode* node7 = BuyNode(7);
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node4->left = node6;
node3->left = node7;
//前序遍历
PrevOrder(node1);
printf("\n");
//中序遍历
InOrder(node1);
printf("\n");
//后序遍历
PostOrder(node1);
printf("\n");
//求树结点的个数
printf("该树结点的个数为:%d\n", TreeSize(node1));
//求叶子结点个数
printf("该树的叶子结点个数为:%d\n", TreeLeafSize(node1));
//树的第k层结点的个数
printf("该树第K层的结点个数为:%d\n", TreeKLevel(node1, 3));
// 二叉树查找值为x的节点:前序遍历
BTNode* ret = BinaryTreeFind(node1, 2);
if (ret != NULL)
{
printf("查找到的位置的数值为%d\n", ret->val);
}
BinaryTreeDestory(&node1);
return 0;
}
主函数部分,申请了7个二叉树的结点,并手动将它们连接起来。然后调用前中后序函数进行遍历打印,其中还有,求树的结点,求叶子结点,求第K层结点,树的销毁等函数。
三、树的遍历:前中后序遍历
1.前序遍历![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/0df76cc5274640280e062729b6877a83.png)
我们知道,前序遍历的顺序是根左右,它会先走根,再走左树,再走右树。对于左树来说,也有它的根左树右树。依次向下,知道遇到null返回。因为对于每一个结点来说,都是根左右的遍历方式,所以我们只需要写一次遍历,然后递归即可。递归的终止值是什么呢?刚才说到,递归只有遇到null才会返回,所以终止条件就是root==null.
//前序遍历
void PrevOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
printf("%d ", root->val);
PrevOrder(root->left);
PrevOrder(root->right);
}
2.前序遍历的递归展开图(只画了左子树的,右子树同理)
前中后序遍历都是一样的逻辑,递归展开图就不再画了。
2.中序遍历
//中序遍历
void InOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
PrevOrder(root->left);
printf("%d ", root->val);
PrevOrder(root->right);
}
3.后序遍历
//后序遍历
void PostOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
PrevOrder(root->left);
PrevOrder(root->right);
printf("%d ", root->val);
}
四、求结点个数
1.求树的结点的个数(这里使用的是前序遍历)
int TreeSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
return 1 + TreeSize(root->left) + TreeSize(root->right);
}
往一个函数中传入一个结点,若结点为空,则直接返回,为不为空则记为一个结点再加上,以该结点为根的左右子树的结点。
2.求叶子结点的个数
//求叶子结点个数
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);
}
将一个根结点传入函数中,如结点为空值,则返回0,若该结点不为空值,且该结点的左右结点为空值,则说明该结点就是叶子结点,则返回1.如果该结点既不是空值,且该结点的左右结点也不为空值,则说明该结点并非叶子结点。该结点还有以它为根的子树,所以应该将它的左右子树传入函数,递归。知道找到子结点,并统计个数。
3.求第K层结点的个数
//树的第k层结点的个数
int TreeKLevel(BTNode* root, int K)
{
if (root == NULL)
{
return 0;
}
if (K == 1)
{
return 1;
}
return TreeKLevel(root->left, K - 1) + TreeKLevel(root->right, K - 1);
}
第K层的结点等于第K-1层的左结点加上右节点。
五、二叉树的销毁(后序遍历)
// 二叉树销毁:后序遍历
void BinaryTreeDestory(BTNode** root)
{
if (*root == NULL)
{
return;
}
BinaryTreeDestory((*root)->left);
BinaryTreeDestory((*root)->right);
free(*root);
*root = NULL;
}
二叉树的销毁采用左右根的方式,最后销毁根结点。遍历方式就是后序遍历。
六、二叉树的查找(前序遍历)
// 二叉树查找值为x的节点:前序遍历
BTNode* BinaryTreeFind(BTNode* root, int x)
{
if (root == NULL)
{
return NULL;
}
if (root->val == x)
{
return root;
}
return BinaryTreeFind(root->left, x) == NULL ? BinaryTreeFind(root->right, x) : BinaryTreeFind(root->left, x);
}
使用二叉树查找某一个值是否存在,存在则返回它的地址,不存在则返回空。使用根左右的前序遍历方式,关键在于最后一句代码:最后一句代码使用了条件判断,如果根查不到,就查左子树,左子树是需要递归遍历的,如果递归遍历的结果是NULL,则返回遍历右子树的值(不管它是否为空),如果左子树遍历找到了,则直接返回左子树的值,不再遍历右子树。
总结:
在这篇内容中,我们用C语言改造一个7个结点的二叉树,然后讲解了二叉树的前中后序的递归遍历方式。还有利用二叉树的递归特性,求二叉树结点的个数,二叉树叶子结点的个数,第K层树的结点的个数。以及二叉树的销毁,还有二叉树的查找等。
喜欢的朋友点个关注,一起学习呀~