【算法】递归算法---作为树的基础知识点【待学习】

只愿长相守 提交于 2020-01-27 09:48:38

https://blog.csdn.net/feizaosyuacm/article/details/54919389

例题:

https://blog.csdn.net/Leo1120178518/article/details/102703350

https://blog.csdn.net/qq_34039315/article/details/78679029

1.递归算法解决问题的特点:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。
2.要求:
递归算法所体现的“重复”一般有三个要求:
一是每次调用在规模上都有所缩小(通常是减半);
二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

3.递归算法的实现(3点:1.入参和递归参数 2.算法 3.终结条件)

3.1 ※使用 递归算法的 前提有两个:
(1) 原问题可以层层分解为类似的子问题,且子问题比原问题的规模更小
(2)规模更小的子问题具有直接解

3.2 设计递归算法的原则是用自身的简单情况来定义自身设计递归算法的方法是:
(1)寻找分解方法,将原问题转化为子问题求解
(2)设计递归出口,也就是说根据最小的子问题,确定递归终止的条件。
3.3 递归的设计思路
(1)确定递归公式(转换为子问题,也就是确定输入参数和输出参数的对应
(2)确定边界(终了)条件

3.4 递归的设计模式
procedure aaa(k:integer);
begin
if k=1 then (边界条件及必要操作)
else begin
aaa(k-1);
(重复的操作);
end;
end;

3.5 递归过程的实现
递归的过程 ,递归进程和递归退层。
递归进程,也就是说递归的过程 i 到 i+1 层,系统需要做三件工作:
(1)保留本层参数与返回地址;
(2)给下层参数赋值
(3)将程序转移到被掉函数的入口

递归退层:也就是从i+1层到i层,系统也应该完成三件工作
(1)保留被调函数的计算结果
(2)恢复上层参数,也就是释放被调函数的数据区
(3)依照被调函数保存的返回地址,将控制转移回调用函数。、

递归函数的运行,以及递归中进层退层的实现,都需要递归机制的支持。
 

二叉树递归相关题思路:

1.传入参数:根节点

2.传递参数:分为左右,两个参数

3.终结条件:1.根节点为nullptr,2.左右子树为nullptr,3.左右递归后的处理

 

2种思维方法:

反向递归(从下往上传值,逐步合并,最后得到一个值)和正向递归(从上往下传值,逐渐发散,最后得到多个值?):

求二叉树最大深度(最后仅需要一个最大值),反向递归:

    int TreeDepth(TreeNode* pRoot)
    {
        //终结条件1:为nullptr的时候,此结点高度为0(由下往上看)
        if(pRoot == NULL){
            return 0;
        }
        //递归基:获得左子树最大值,和右子树最大值,将其中更大的+1再传递给上层
        int left = TreeDepth(pRoot->left);
        int right = TreeDepth(pRoot->right);
        //终结条件2:左右递归完毕
        return (left > right) ? (left + 1) : (right + 1);
    }
//或者
int getHigh(BinaryTreeNode* T)
{
	int high = 0;
	if(T != nullptr)
	{
		int lhigh = getHigh(T->lchild);
		int rhigh = getHigh(T->rchild);
		//int maxLayer = (lhigh>rhigh?lhigh:rhigh);
		int maxLayer = max(lhigh,rhigh);
		high = maxLayer +1;
	}
	return high;
}

求二叉树各个叶子结点的深度(返回vector),正向递归:

vector<int> sumResult;
//第一次传入sum为0
vector<int> sumTree(BinaryTreeNode* T,int sum)
{
	//2 终结条件1:如果传递下来为nullptr时,表示其中一边为nullptr,另一边非nullptr,直接返回
	if(T ==nullptr)
	{
		return sumResult;
	}

	//1.考虑一般情况,最小递归基:上面传递下来的和,
	//加上自身,如果左右子叶为空,则为叶子结点
	//否则继续递归,传递下去
	sum =(sum + T->value);
	if(T->lchild == nullptr &&T->rchild ==nullptr)
	{
		sumResult.push_back(sum);
	}
	//1.1 往左和往右分别传递,
	sumTree(T->lchild,sum);
	sumTree(T->rchild,sum);
	return sumResult;
}

例题:

https://blog.csdn.net/songyunli1111/article/details/80138757

重建二叉树这里就以 后序遍历 输出展示,这里给出上述博客中描述的几个遍历方法的特点:

特性A,对于前序遍历,第一个肯定是根节点;
特性B,对于后序遍历,最后一个肯定是根节点;
特性C,利用前序或后序遍历,确定根节点,在中序遍历中,根节点的两边就可以分出左子树和右子树;
特性D,对左子树和右子树分别做前面3点的分析和拆分,相当于做递归,即可重建出完整的二叉树
※注:此处ABC也就是子问题,D也就是重复递归的点,还需要一个边界条件就齐活!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!