树是数据结构中非常重要的一种,在计算机的各方个面都有他的身影
此篇文章主要介绍二叉树的基本操作
这里我们使用char
,因为二叉树的创建我们会使用递归创建,需要传入一个字符串进行操作
typedef char BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
我们通过前序遍历的数组"123###45##6##"
构建二叉树
这里讲一下我使用递归做题时的一些做题感受方法:
接下来我会仔细带着大家仔细领悟,熟能生巧,同学们一定不要气馁
先解释一下这个函数传参的意义:
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
a就是我们传参的字符数组
pi是我们字符数组的下标,为什么需要下标的地址呢,因为形参的改变不会影响实参
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
if (a[*pi] == '#')
{
(*pi)++;
return NULL;
}
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
if (root == NULL)
{
perror("malloc fail");
return;
}
root->data = a[(*pi)++];
root->left = BinaryTreeCreate(a, pi);
root->right = BinaryTreeCreate(a, pi);
return root;
}
root->val
进行赋值,再将root
的左右子树进行连接root
节点,也进行了赋值,root
的左右节点也都分别使用BinaryTreeCreate(a, n, pi)
这个函数进行连接,我们已经把此函数当做可以完成既定任务的,不需要过多纠结,此时我们在加一个返回值root
,就完成了此次函数的创建二叉树的递归图:
大家也可以自己动手画一下递归展开图
有了以上的思路就可以很简单的实现了
void BinaryTreePrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
printf("%c ", root->data);
BinaryTreePrevOrder(root->left);
BinaryTreePrevOrder(root->right);
}
代码也很简洁
就像下图这样,将这个程序当成可以完成任务的函数。
printf("%c ", root->data);//进行本次的任务
BinaryTreePrevOrder(root->left);//遍历左子树
BinaryTreePrevOrder(root->right);//遍历左子树
与前序遍历一致
void BinaryTreePrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
BinaryTreePrevOrder(root->left);
printf("%c ", root->data);
BinaryTreePrevOrder(root->right);
}
void BinaryTreePrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
BinaryTreePrevOrder(root->left);
BinaryTreePrevOrder(root->right);
printf("%c ", root->data);
}
int BinaryTreeSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
return BinaryTreeSize(root->left) +
BinaryTreeSize(root->right) + 1;
}
NULL
int BinaryTreeLeafSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
if (root->left == NULL && root->right == NULL)
{
return 1;
}
return BinaryTreeLeafSize(root->left) +
BinaryTreeLeafSize(root->right);
}
int BinaryTreeLevelKSize(BTNode* root, int k)
{
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return BinaryTreeLevelKSize(root->left, k - 1) +
BinaryTreeLevelKSize(root->right, k - 1);
}
1.结束条件有两个,当为NULL
或为目标层数时为结束
2. 分治:这个的分治并不像上边的简单了,我们需要root的第k层转化为root->左子树的k-1层与root->right的k-1层,将K
也作为函数传参,每次减1
3. 返回第k层节点个数
我们先来看这样一段代码,相信有许多小伙伴在遇到
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
{
return NULL;
}
if (root->data == x)
{
return root;
}
BinaryTreeFind(root->left, x);
BinaryTreeFind(root->right, x);
return NULL;
}
乍一看好像没什么问题,不就是前序遍历嘛,
不然,实则我们并没有记录找到的地址,像下图一样
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
{
return NULL;
}
if (root->data == x)
{
return root;
}
BTNode* ret1 = BinaryTreeFind(root->left, x);
if (ret1)
{
return ret1;
}
BTNode* ret2 = BinaryTreeFind(root->right, x);
if (ret2)
{
return ret2;
}
return NULL;
}
NULL
或目标值ret
值并返回使用后序遍历,因为前序与中序需要记录当前被销毁的左右节点地址
void BinaryTreeDestory(BTNode* root)
{
if (root == NULL)
{
return;
}
BinaryTreeDestory(root->left);
BinaryTreeDestory(root->right);
free(root);
}
持续更新中…