递归的本质是通过栈来保存状态,然后再次调用自己进入新的状态,然后函数返回的时候回到上次保存的状态。
如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作,就是没有回溯过程,所以我们可以直接将尾递归写成循环
更一般的递归,想要转化为非递归,就需要模拟栈(手写栈)的行为。
遍历的递归和非递归实现:
#include<cstdio> #include<stack> using namespace std; struct node{ int id; node *l=NULL,*r=NULL; }a[100]; void PreOrderTraverse(node i){//递归先序遍历 printf("%d ",i.id);//输出根 if(i.l)PreOrderTraverse(*i.l);//遍历左子树 if(i.r)PreOrderTraverse(*i.r);//遍历右子树 } void InOrderTraverse(node i){//递归中序遍历 if(i.l)InOrderTraverse(*i.l);//遍历左子树 printf("%d ",i.id);//输出根 if(i.r)InOrderTraverse(*i.r);//遍历右子树 } void PostOrderTraverse(node i){//递归后序遍历 if(i.l)PostOrderTraverse(*i.l);//遍历左子树 if(i.r)PostOrderTraverse(*i.r);//遍历右子树 printf("%d ",i.id);//输出根 } void PreOrderTraverse(node* i){//非递归先序遍历 stack<node>s; node x; while(i||!s.empty()){ while(i){ s.push(*i); printf("%d ",i->id);//输出根 i=i->l;//遍历左子树 } x=s.top();s.pop(); i=x.r;//遍历右子树 } } void InOrderTraverse(node* i){//非递归中序遍历 stack<node>s; node x; while(i||!s.empty()){ while(i){ s.push(*i); i=i->l;//遍历左子树 } x=s.top();s.pop(); printf("%d ",x.id);//输出根 i=x.r;//遍历右子树 } } void PostOrderTraverse(node* i){//非递归后序遍历 stack<pair<node,bool> >s; pair<node,bool> x; while(i||!s.empty()){ while(i){ s.push(make_pair(*i,0)); i=i->l;//遍历左子树 } x=s.top();s.pop(); if(x.second)printf("%d ",x.first.id);//如果右子树遍历过则输出根 else s.push(make_pair(x.first,1)),i=x.first.r;//如果右子树没遍历则遍历右子树 } } int main(){ for(int i=1;i<99;i++){ a[i].id=i; if(i%2)a[i>>1].r=&a[i]; else a[i>>1].l=&a[i]; } InOrderTraverse(a[1]);printf(" "); InOrderTraverse(&a[1]);printf(" "); PreOrderTraverse(a[1]);printf(" "); PreOrderTraverse(&a[1]);printf(" "); PostOrderTraverse(a[1]);printf(" "); PostOrderTraverse(&a[1]);printf(" "); return 0; }