前言:
有很多复杂算法都包含了递归算法,特别是关于树形数据结构遍历的情景,所以正确深入理解递归算法是很有必要的。
一、递归函数的基本概念
递归函数机制理解:调用函数的静态和动态机制理解:调用函数和被调用函数虽然是同一个静态代码,但是运行时被函数运行的栈空间独立于调用函数的栈空间,调用点不同,函数状态栈地址也不同,所以运行时调用函数和被调用函数在代码副本还是数据副本上都是完全不同的,只有通过返回值和调用点进行联系。
递归的调用形式:直接递归调用F1->F1,间接递归F1->F2->F1,很多情况下是直接递归调用。
递归函数优劣点:递归函数比较消耗栈资源,实现简单(内部调用逻辑却比较复杂),但是效率没有非递归版本效率高。
二、递归函数内部调用逻辑理解:
浅层次理解:
1.递归函数需要一个终止条件。
2.递归函数到终止条件,会沿路出栈对称返回。
深层次理解:
I、深究内部过程,调用点和变量寄存器:压栈过程,调用点关联,除了调用点传入参数和返回值外的代码变量都因被拷贝了一份而作用域无效
递归函数就是函数调用和被调用的压栈关系,只有找到都会递归调用,所以递归遍历都是深度遍历。
II、区分终止条件:递归终止条件多样性,区分那些是终止条件那些不是
递归函数的终止条件就是在不断的递归调用下最后会发生不再调用递归函数的情况,可以是if判断也可以是for/while判断。
III、理解出栈返回过程:终止后出栈调用点返回,继续执行函数体内因返回点没有得到执行的代码
一般递归是为了遍历或者查找,如果查找终止条件在递归遍历前面,那么不用全部遍历找到就会返回;如果查找终止条件在递归遍历后面,那么需要全部遍历才会返回。
三、一个遍历3ds Max导出节点的递归算法的模拟示例
RecursiveFunc.h文件:
#ifndef RECURSIVEFUNC_H_
#define RECURSIVEFUNC_H_
#include <string>
#include <list>
using namespace std;
typedef struct tagMaxTreeNode
{
int m_nIndex;
string m_strName;
tagMaxTreeNode(int nIndex, const string& strName)
{
m_nIndex = nIndex;
m_strName = strName;
}
void AddChild(tagMaxTreeNode* pChild)
{
m_listChild.push_back(pChild);
}
list<tagMaxTreeNode*> m_listChild;
}MaxTreeNode;
template <class T>
class MaxTree
{
public:
MaxTree()
{
m_root = NULL;
}
~MaxTree()
{}
void AddNode(T *pParent, T *pChild)
{
if( pParent == NULL )
{
m_root = pParent;
return;
}
else
{
pParent->AddChild(pChild);
}
}
void BrowseF( T* pNode)
{
printf("BrowseF:Recursive Call nIndex: %d\n", pNode->m_nIndex);
// 这里if是终止条件
if( pNode->m_nIndex < 10 )
{
printf("BrowseF:Condition Hit nIndex: %d\n", pNode->m_nIndex);
return;
}
list<T*>::iterator itrChild = pNode->m_listChild.begin();
// 这里for也是是终止条件,因为pNode是子节点的了
for(; itrChild != pNode->m_listChild.end(); ++itrChild)
{
BrowseF( *itrChild);
}
}
void BrowseL( T* pNode)
{
printf("BrowseF:Recursive Call nIndex: %d\n", pNode->m_nIndex);
list<T*>::iterator itrChild = pNode->m_listChild.begin();
// 这里for是终止条件,因为pNode是子节点的了
for(; itrChild != pNode->m_listChild.end(); ++itrChild)
{
BrowseF( *itrChild);
}
// 这里if不是终止条件
if( pNode->m_nIndex < 10 )
{
printf("BrowseF:Condition Hit nIndex: %d\n", pNode->m_nIndex);return;
}
}
private: T* m_root;
};
#endif
main1.cpp文件:
#include "stdafx.h"
#include "RecursiveFunc.h"
int _tmain(int argc, _TCHAR* argv[])
{
MaxTreeNode node1(1, "node1");
MaxTreeNode node2(10, "node2");
MaxTreeNode node3(100, "node3");
MaxTreeNode node4(1000, "node4");
MaxTreeNode node5(10000, "node5");
/*MaxTreeNode node1(1000, "node1");
MaxTreeNode node2(1000, "node2");
MaxTreeNode node3(100, "node3");
MaxTreeNode node4(100, "node4");
MaxTreeNode node5(1, "node5");*/
MaxTree<MaxTreeNode> TestTree;
TestTree.AddNode(NULL, &node1);
TestTree.AddNode(&node1, &node2);
TestTree.AddNode(&node1, &node3);
TestTree.AddNode(&node2, &node4);
TestTree.AddNode(&node3, &node5);
printf("------------TestTree.BrowseF(&node1);-------\n");
TestTree.BrowseF(&node1);
printf("------------TestTree.BrowseL(&node1);-------\n");
TestTree.BrowseL(&node1);
return 0;
}
输出结果:
main2.cpp:
#include "stdafx.h"
#include "RecursiveFunc.h"
int _tmain(int argc, _TCHAR* argv[])
{
/*MaxTreeNode node1(1, "node1");
MaxTreeNode node2(10, "node2");
MaxTreeNode node3(100, "node3");
MaxTreeNode node4(1000, "node4");
MaxTreeNode node5(10000, "node5");*/
MaxTreeNode node1(10000, "node1");
MaxTreeNode node2(1000, "node2");
MaxTreeNode node3(100, "node3");
MaxTreeNode node4(100, "node4");
MaxTreeNode node5(1, "node5");
MaxTree<MaxTreeNode> TestTree;
TestTree.AddNode(NULL, &node1);
TestTree.AddNode(&node1, &node2);
TestTree.AddNode(&node1, &node3);
TestTree.AddNode(&node2, &node4);
TestTree.AddNode(&node3, &node5);
printf("------------TestTree.BrowseF(&node1);-------\n");
TestTree.BrowseF(&node1);
printf("------------TestTree.BrowseL(&node1);-------\n");
TestTree.BrowseL(&node1);
return 0;
}
输出结果: