本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1. 二叉树节点个数 (引进分治思想)
==方法一:(遍历+计数)==
遍历中会新建栈帧,每个栈帧都定义一个count没法加到一起,所以定义一个全局变量、或静态变量
int count = 0;//全局变量
//思想:遍历+计数
int BTreeSize(BTNode* root)
{
if (root == NULL)
return;
count++;
BTreeSize(root->left);
BTreeSize(root->right);
return count;
}
int main()
{
count = 0;
printf("size:%d\n", BTreeSize(tree));
count = 0;
printf("size:%d\n", BTreeSize(tree));
}
缺点:多次调用count会累加,每次调用还得初始化一次count(还会有线程安全的问题,这个以后linux学了大家就知道了)
改进版:传变量地址
//思想:遍历+计数
void BTreeSize(BTNode* root, int* pCount)
{
if (root == NULL)
return;
(*pCount)++;
BTreeSize(root->left, pCount);
BTreeSize(root->right, pCount);
}
int main()
{
int count1 = 0;
BTreeSize(tree, &count1);
printf("size:%d\n", count1);
}
==方法二:(分治:把复杂问题分成更小规模子问题···直到子问题不可再分割,能直接能出结果)==
思路:分治(超级套娃)
:one:空数,最小规模的子问题,节点个数返回0
:two:非空,左子树节点个数+右子树节点个数+1(自己)
图解:
//思想:分治
int BTreeSize(BTNode* root)
{
return root == NULL ? 0 : BTreeSize(root->left) + BTreeSize(root->right) + 1;
}
2. 二叉树叶子节点个数
思路:叶子节点个数 = 左子树的叶子节点 + 右子树的叶子节点
int BTreeLeafSize(BTNode* root)
{
if (root == NULL)
return 0;
//判断是否为叶子节点
if (root->left == NULL && root->right == NULL)
return 1;
return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
}
3. 二叉树第k层节点个数
不想画图了╮(๑•́ ₃•̀๑)╭,自己尝试画画吧
假如我要求第三层的节点个数,怎么才能知道那是第三层呢?
我可以在第一层求它下下层的节点个数
我可以在第二层求它下一层的节点个数
就可以转换成求第一层向下k-1层的节点个数
思想:
:one:空数,返回0
:two:非空,且k == 1,返回1
:three:非空,且k > 1,转换成左子树k-1层节点个数 + 右子树k-1层节点个数
//第k层节点个数
int BTreeLevelSize(BTNode* root, int k)
{
assert(k >= 1);
if (root == NULL)
return 0;
if (k == 1)
return 1;
return BTreeLevelSize(root->left, k - 1) + BTreeLevelSize(root->right, k - 1);
}
4. 二叉树层数
思路:层数 =
左子树高度和右子树高度中大的那个+1
int BTreeDepth(BTNode* root)
{
if (root == NULL)
return 0;
int leftDepth = BTreeDepth(root->left);
int rightDepth = BTreeDepth(root->right);
return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
5. 二叉树查找值为x的节点
思路:从根开始找,按照前序遍历顺序找,找到就返回地址,找不到就返回NULL
BTNode* BTFind(BTNode* root, BTDataType x)
{
if (root == NULL)
return NULL;
if (root->data == x)
return root;
BTNode* ret1 = BTFind(root->left, x);
if (ret1)
return ret1;
BTNode* ret2 = BTFind(root->right, x);
if (ret2)
return ret2;
return NULL;
}
6. 判断是否为完全二叉树
还记得上面写的层序遍历吗?
我们要运用它巧妙地解决这道题。
思路:
层序遍历,空节点也入队列、出队列
当出到第一个NULL时停止入队列,只出队列
判断NULL后是否全为NULL,还是说其中有节点的值乱入(下图红色部分)
//是否为完全二叉树
//层序遍历,空节点也出,判断空之后是否都为空
bool BTreeComplete(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root)
{
QueuePush(&q, root);
}
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
//出到空,就判断后续
if (front == NULL)
break;
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
//出到非空——不是完全二叉树
if (front)
return false;
}
QueueDestory(&q);
return true;
}
7. 二叉树的销毁
玩完之后要记得销毁哦!
想一想,能不能从根节点开始销毁呢?
不能,否则就找不到下面的节点了
所以,我们要用后续遍历的顺序来销毁,最后销毁根节点
void BTDestory(BTNode* root)
{
if (root == NULL)
return;
BTDestory(root->left);
BTDestory(root->right);
free(root);
}
小结: 这节的内容难度又上了一个台阶,考察的不仅是对数据结构的理解,还有c语言阶段对递归的理解。 加油哦,就算走得慢也比原地踏步好。:muscle: