递归的本质是通过栈来保存状态,然后再次调用自己进入新的状态,然后函数返回的时候回到上次保存的状态。
尾递归可以直接转化成循环,这里不多做分析
更一般的递归,想要转化为非递归,就需要模拟栈的行为。
首先需要自己建个栈。栈保存的东西是一个记录,包括所有局部变量的值,执行到的代码位置。
首先讲局部变量初始化位一开始的状态,然后进入一个循环
执行代码时,遇到递归,就制作状态压栈保存,然后更新局部变量进入下一层。
如果一个调用结束了,就要返回上层状态。直接讲栈里的记录弹出,拿来更新当前状态即可。
某个调用结束时如果栈为空则所有调用都结束,退出主循环。
下面的代码给出中序遍历的非递归实现:
struct record{ node* a; int state; record(node* a,int state):a(a),state(state){} }; void non_recursive_inorder(){ stack<record> s; node* cur=root; //初始化状态 int state=0; while(1){ if(!cur){ //如果遇到null结点,返回上一层 if(cur == root)break;//如果没有上一层,退出循环 cur=s.top().a; state=s.top().state; //返回上层状态 s.pop(); }else if(state == 0){ //状态位0,执行第一个递归inorder(cur->left); s.push(record(cur,1));//保存本层状态 cur=cur->left; //更新到下层状态 state=0; }else if(state == 1){ //状态为1,执行print和inorder(cur->right) printf("%d ",cur->x); s.push(record(cur,2)); //保存本层状态 cur=cur->right; //进入下层状态 state=0; }else if(state == 2){ //状态2,函数结束,返回上层状态 if(cur == root)break; //初始结点的退出状态,遍历结束 cur=s.top().a; //返回上层状态 state=s.top().state; s.pop(); } } putchar(10); }
快速排序的非递归实现:
#include<stdio.h> int partition(int a[],int l,int r){ int key=a[l],i=l,j=r; while(i<j){ while(i<j && a[j] >= key) j--; if(i<j) a[i++]=a[j]; while(i<j && a[i] <=key) i++; if(i<j) a[j--]=a[i]; } a[i]=key; return i; } void qsort(int a[],int l,int r){ //boundary case if(l>=r) return; //state 0 int mid=partition(a,l,r); qsort(a,l,mid-1); //state 1 qsort(a,mid+1,r); //state 2 } struct recorc{ int l,r,mid; //local virables. a[] never changed, no need to save. int state; }stack[100000]; void nun_recursive_qsort(int a[],int l,int r){ int state=0,top=0; int mid; while(1){ if(l>=r){ //boundary case, return previous level if(top == 0) break; //end of recursion top--; l=stack[top].l; //end of function, update to previous state r=stack[top].r; mid=stack[top].mid; state=stack[top].state; }else if(state == 0){ mid=partition(a,l,r); stack[top].l=l; //recutsive call, push current state into stack stack[top].r=r; stack[top].mid=mid; stack[top].state=1; top++; r=mid-1; state=0; //don't forget to update state value }else if(state == 1){ stack[top].l=l; stack[top].r=r; //recursive call, push current state into stack stack[top].mid=mid; stack[top].state=2; top++; l=mid+1; state=0; }else if(state == 2){ if(top == 0) break; //end of recursion top--; l=stack[top].l; r=stack[top].r; mid=stack[top].mid; state=stack[top].state; } } }