引言
对于树与递归而言,往往是返回的过程总能让一些初学者头昏脑胀,下面将从函数返回类型的角度,解析函数的递归。
首先要搞明白递归的构成:1.子问题 2. 结束语句
其次要搞明白,函数的返回是返回到上一层调用此函数的地方去,而不是直接返回到“根部”函数处。
目录
一、分类
首先将返回类型分为两大类 : void 类型 与 非 void类型。
void类型
举例
void PrevOrder(BTNode* root)
{
if (root == NULL)
printf("N ");
return;
}
printf("%d ", root->date);
PrevOrder(root->left);
PrevOrder(root->right);
//不能写换行,否则每次递归都会打印换行
}
这是一段前序遍历代码。
其返回类型是void类型。
其递归调用过程,在代码中具体表现为以下两句代码
PrevOrder(root->left);
PrevOrder(root->right);
其在物理中,具体表现为函数栈帧的不断创建与销毁, 当 PrevOrder(root->left) 此段代码不断递归调用完成之后
其函数栈帧销毁,此时回到上一层调用它的函数,继续执行上一层函数。
非void类型
例一
// 二叉树结点个数
int BTreeSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
int leftsize = BTreeSize(root->left);
int rightsize = BTreeSize(root->right);
return leftsize + rightsize + 1;
}
此段代码求的是二叉树的节点个数。
可以观察到,返回类型是int类型。
其递归过程,在代码中,具体体现在以下两句代码。
int leftsize = BTreeSize(root->left);
int rightsize = BTreeSize(root->right);
return leftsize + rightsize + 1;
在物理中,对于上面三句代码。当最后一层函数调用结束,最后一层函数
int leftsize = BTreeSize(root->left);
int rightsize = BTreeSize(root->right);
的栈帧销毁之后,会通过 return leftsize + rightsize + 1;语句,返回到上一层调用该段代码的 BTreeSize(root->left) 这个函数处。从而倒数第二层的 int leftsize = BTreeSize(root->left);这段语句执行结束,进而执行 int leftsize = BTreeSize(root->left)的递归过程。
最终倒数第二层执行结束,会再次通过 int leftsize = BTreeSize(root->left); 语句,返回到倒数第三层 int leftsize = BTreeSize(root->left); 的 函数递归调用处。
例二
// 求叶子节点的个数
int BTreeLeafSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
//此处root一定不为空
if (root->left == NULL && root->right == NULL)
{
return 1;
}
return BTreeLeafSize(root->left) + BTreeLeafSize(root->right); //会在此处不断返回本层的结果,返回到上一层的栈帧里的函数调用处。
}
这段代码是求叶子节点的个数。
递归调用具体体现在 return BTreeLeafSize(root->left) + BTreeLeafSize(root->right); 该段代码处。
逻辑雷同例一,当最后一层栈帧 BTreeLeafSize(root->left) 完成任务并销毁之后,会生成BTreeLeafSize(root->right); 的栈帧。当最后一层栈帧全部调用完成之后,会通过return 语句,返回到上一层(倒数第二层) BTreeLeafSize(root->left)语句处,再执行倒数第二层的BTreeLeafSize(root->right)该段代码。
从而实现层层递归,最终由“根函数”,返回层层递归后的结果。
因此:
可以将二叉树的递归,通过二叉树结构图示去理解。
结构的不断分叉,代表递归按一条支路的不断展开。(先通过一条支路展开!!)递归返回时或栈帧销毁时,同样是按照二叉树的结构去返回!!!