二叉树的节点个数

假设二叉树如下图所示:

image-20230712095939682

要想知道二叉树的节点个数,我们通常会想到遍历二叉树的同时使用一个变量来记录,假设变量为size,使用前序遍历,每遍历一个结点让size++,可设置程序如下:

int TreeSize(BTNode* root)
{
	int size = 0;
	if (root == NULL)
	{
		return 0;
	}
	size++;
	TreeSize(root->left);
	TreeSize(root->right);
	return size;
}

但是我们需要注意的是size变量是局部变量,是建立在函数栈帧中的,在递归程序中,每建立一个函数栈帧都会创建一个size局部变量,因此这里的size++是对不同函数栈帧中的size进行处理的,并不能达到我们想要的效果。

那如果我们设置一个size静态变量是否可以呢?

int TreeSize(BTNode* root)
{
	static int size = 0;
	if (root == NULL)
	{
		return 0;
	}
	size++;
	TreeSize(root->left);
	TreeSize(root->right);
	return size;
}

size被static修饰之后就不再存储在栈区,而是存储在静态区,静态局部变量(静态局部变量只能在定义函数内使用)是在编译期间就指定的,所以运行期间每次递归都不会再重新创建变量size,所以每次++的时候用的是同一个size。

但是设置静态变量后第一次调用TreeSize函数时,可以正确的计算出结点个数,但是当我们再次调用的时候就不能正确计算出来了,会发现结果越来越大,因为静态变量和全局变量的作用域都是整个程序,只有在第一次进入函数时才会进行初始化,

这是因为静态变量与全局变量的作用域都是整个程序,所以只有在第一次进入函数时才会在定义的同时进行初始化,可以通过将size = 0直接把 size 赋值为0,但是如果这样的话找不到合适的位置将size赋值为0。

我们可以设置一个全局变量size,然后每次在调用TreeSize函数的时候将size变量赋值为0,同时TreeSize函数不用再有返回值。

int size = 0;
void TreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	size++;
	TreeSize(root->left);
	TreeSize(root->right);
}

测试:

int main()
{
    BTNode* root = CreatBinaryTree();
    TreeSize(root);
    printf("%d\n", size);//输出6
    size = 0;
    TreeSize(root);
    printf("%d\n", size);//输出6
}

这种办法并不好,每次还要将size置为0,我们可以通过使用分治思想,把大问题分解成小问题,逐层统计:通过计算节点子树的节点数量,并把统计到的节点数量加一(即加上结点本身),返回给该节点的父节点。

int TreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return TreeSize(root->left) + TreeSize(root->right) + 1;
}