赞
踩
a)递归方式:
- void preorder_recursive(Bitree T) /* 先序遍历二叉树的递归算法 */
- {
- if (T) {
- visit(T); /* 访问当前结点 */
- preorder_recursive(T->;lchild); /* 访问左子树 */
- preorder_recursive(T->;rchild); /* 访问右子树 */
- }
- }
b)非递归方式
- void preorder_nonrecursive(Bitree T) /* 先序遍历二叉树的非递归算法 */
- {
- initstack(S);
- push(S,T); /* 根指针进栈 */
- while(!stackempty(S)) {
- while(gettop(S,p)&&p) { /* 向左走到尽头 */
- visit(p); /* 每向前走一步都访问当前结点 */
- push(S,p->;lchild);
- }
- pop(S,p);
- if(!stackempty(S)) { /* 向右走一步 */
- pop(S,p);
- push(S,p->;rchild);
- }
- }
- }

a)递归方式
- void inorder_recursive(Bitree T) /* 中序遍历二叉树的递归算法 */
- {
- if (T) {
- inorder_recursive(T->;lchild); /* 访问左子树 */
- visit(T); /* 访问当前结点 */
- inorder_recursive(T->;rchild); /* 访问右子树 */
- }
- }
b)非递归方式
- void inorder_nonrecursive(Bitree T)
- {
- initstack(S); /* 初始化栈 */
- push(S, T); /* 根指针入栈 */
-
- while (!stackempty(S)) {
- while (gettop(S, p) && p) /* 向左走到尽头 */
- push(S, p->;lchild);
- pop(S, p); /* 空指针退栈 */
- if (!stackempty(S)) {
- pop(S, p);
- visit(p); /* 访问当前结点 */
- push(S, p->;rchild); /* 向右走一步 */
- }
- }
- }

- void postorder_recursive(Bitree T) /* 中序遍历二叉树的递归算法 */
- {
- if (T) {
- postorder_recursive(T->;lchild); /* 访问左子树 */
- postorder_recursive(T->;rchild); /* 访问右子树 */
- visit(T); /* 访问当前结点 */
- }
- }
- typedef struct {
- BTNode* ptr;
- enum {0,1,2} mark;
- } PMType; /* 有mark域的结点指针类型 */
-
- void postorder_nonrecursive(BiTree T) /* 后续遍历二叉树的非递归算法 */
- {
- PMType a;
- initstack(S); /* S的元素为PMType类型 */
- push (S,{T,0}); /* 根结点入栈 */
- while(!stackempty(S)) {
- pop(S,a);
- switch(a.mark)
- {
- case 0:
- push(S,{a.ptr,1}); /* 修改mark域 */
- if(a.ptr->;lchild)
- push(S,{a.ptr->;lchild,0}); /* 访问左子树 */
- break;
- case 1:
- push(S,{a.ptr,2}); /* 修改mark域 */
- if(a.ptr->;rchild)
- push(S,{a.ptr->;rchild,0}); /* 访问右子树 */
- break;
- case 2:
- visit(a.ptr); /* 访问结点 */
- }
- }
- }

4)如何实现递归与非递归的转换
通常,一个函数在调用另一个函数之前,要作如下的事情:a)将实在参数,返回地址等信息传递
给被调用函数保存; b)为被调用函数的局部变量分配存储区;c)将控制转移到被调函数的入口.
从被调用函数返回调用函数之前,也要做三件事情:a)保存被调函数的计算结果;b)释放被调
函数的数据区;c)依照被调函数保存的返回地址将控制转移到调用函数.
所有的这些,不论是变量还是地址,本质上来说都是"数据",都是保存在系统所分配的栈中的.
ok,到这里已经解决了第一个问题:递归调用时数据都是保存在栈中的,有多少个数据需要保存
就要设置多少个栈,而且最重要的一点是:控制所有这些栈的栈顶指针都是相同的,否则无法实现
同步.
下面来解决第二个问题:在非递归中,程序如何知道到底要转移到哪个部分继续执行?回到上
面说的树的三种遍历方式,抽象出来只有三种操作:访问当前结点,访问左子树,访问右子树.这三
种操作的顺序不同,遍历方式也不同.如果我们再抽象一点,对这三种操作再进行一个概括,可以
得到:a)访问当前结点:对目前的数据进行一些处理;b)访问左子树:变换当前的数据以进行下一次
处理;c)访问右子树:再次变换当前的数据以进行下一次处理(与访问左子树所不同的方式).
下面以先序遍历来说明:
- void preorder_recursive(Bitree T) /* 先序遍历二叉树的递归算法 */
- {
- if (T) {
- visit(T); /* 访问当前结点 */
- preorder_recursive(T->;lchild); /* 访问左子树 */
- preorder_recursive(T->;rchild); /* 访问右子树 */
- }
- }
- //f(n) = n + 1; (n <2)
- //f[n/2] + f[n/4](n >;= 2);
- //
- //这个例子相对简单一些,递归程序如下:
- int f_recursive(int n)
- {
- int u1, u2, f;
-
- if (n < 2)
- f = n + 1;
- else {
- u1 = f_recursive((int)(n/2));
- u2 = f_recursive((int)(n/4));
- f = u1 * u2;
- }
-
- return f;
- }

- int f_nonrecursive(int n)
- {
- int stack[20], flag[20], cp;
-
- /* 初始化栈和栈顶指针 */
- cp = 0;
- stack[0] = n;
- flag[0] = 0;
-
- while (cp >;= 0) {
- switch(flag[cp]) {
- case 0: /* 访问的是根结点 */
- if (stack[cp] >;= 2) { /* 左子树入栈 */
- flag[cp] = 1; /* 修改标志域 */
- cp++;
- stack[cp] = (int)(stack[cp - 1] / 2);
- flag[cp] = 0;
- } else { /* 否则为叶子结点 */
- stack[cp] += 1;
- flag[cp] = 2;
- }
- break;
- case 1: /* 访问的是左子树 */
- if (stack[cp] >;= 2) { /* 右子树入栈 */
- flag[cp] = 2; /* 修改标志域 */
- cp += 2;
- stack[cp] = (int)(stack[cp - 2] / 4);
- flag[cp] = 1;
- } else { /* 否则为叶子结点 */
- stack[cp] += 1;
- flag[cp] = 2;
- }
- break;
- case 2: /* */
- if (flag[cp - 1] == 2) { /* 当前是右子树吗? */
- /*
- * 如果是右子树, 那么对某一棵子树的后序遍历已经
- * 结束,接下来就是对这棵子树的根结点的访问
- */
- stack[cp - 2] = stack[cp] * stack[cp - 1];
- flag[cp - 2] = 2;
- cp = cp - 2;
- } else
- /* 否则退回到后序遍历的上一个结点 */
- cp--;
- break;
- }
- }
-
- return stack[0];
- }

递归算法如下:
- void swap(int array[], int low, int high)
- {
- int temp;
-
- temp = array[low];
- array[low] = array[high];
- array[high] = temp;
- }
-
- int partition(int array[], int low, int high)
- {
- int p;
-
- p = array[low];
-
- while (low < high) {
- while (low < high && array[high] >;= p)
- high--;
- swap(array,low,high);
- while (low < high && array[low] <= p)
- low++;
- swap(array,low,high);
- }
-
- return low;
- }
-
- void qsort_recursive(int array[], int low, int high)
- {
- int p;
-
- if(low < high) {
- p = partition(array, low, high);
- qsort_recursive(array, low, p - 1);
- qsort_recursive(array, p + 1, high);
- }
- }

- void qsort_nonrecursive(int array[], int low, int high)
- {
- int m[50], n[50], cp, p;
-
- /* 初始化栈和栈顶指针 */
- cp = 0;
- m[0] = low;
- n[0] = high;
-
- while (m[cp] < n[cp]) {
- while (m[cp] < n[cp]) { /* 向左走到尽头 */
- p = partition(array, m[cp], n[cp]); /* 对当前结点的访问 */
- cp++;
- m[cp] = m[cp - 1];
- n[cp] = p - 1;
- }
- /* 向右走一步 */
- m[cp + 1] = n[cp] + 2;
- n[cp + 1] = n[cp - 1];
- cp++;
- }
- }

- akm(m, n) = n + 1; (m = 0时)
- akm(m - 1, 1); (n = 0时)
- akm(m - 1, akm(m, n - 1)); (m != 0且n != 0时)
递归算法如下:
- int akm_recursive(int m, int n)
- {
- int temp;
-
- if (m == 0)
- return (n + 1);
- else if (n == 0)
- return akm_recursive(m - 1, 1);
- else {
- temp = akm_recursive(m, n - 1);
- return akm_recursive(m - 1, temp);
- }
- }
好了,让我们回到递归与非递归的世界中,继续未完的旅途.
这道题的难点就是确定递归调用树的情况,因为从akm函数的公式可以看到,有三个递归调用,一般
而言,有几个递归调用就会有几棵递归调用的子树,不过这只是一般的情况,不一定准确,也不一定非要
机械化的这么作,因为通常情况下我们可以做一些优化,省去其中的一些部分,这道题就是一个例子.
递归调用树的分析:a)是当m=0时是叶子结点;b)左子树是akm(m - 1, akm(m, n - 1))调用中的
akm(m, n - 1)调用,当这个调用结束得出一个值temp时,再调用akm(m - 1, temp),这个调用是右子树
.c)从上面的分析可以看出,这个递归调用树是后序遍历的树.
栈的分析:要保存的数据是m, n,当n = 0 或 m = 0时开始退栈,当n = 0时把上一层栈的m值变为
m - 1,n变为1,当m = 0时把上一层栈的m值变为0,n变为n + 1.从这个分析过程可以看出,我们省略了
当n = 0时的akm(m - 1, 1)调用,原来在系统机械化的实现递归调用的过程中,这个调用也是一棵子树,
不过经过分析,我们用修改栈中数据的方式进行了改进.
- int akm_nonrecursive(int m, int n)
- {
- int m1[50], n1[50], cp;
-
- cp = 0;
- m1[0] = m;
- n1[0] = n;
-
- do {
- while (m1[cp] >; 0) { /* 压栈, 直到m1[cp] = 0 */
- while (n1[cp] >; 0) { /* 压栈, 直到n1[cp] = 0 */
- cp++;
- m1[cp] = m1[cp - 1];
- n1[cp] = n1[cp - 1] - 1;
- }
- /* 计算akm(m - 1, 1),当n = 0时 */
- m1[cp] = m1[cp] - 1;
- n1[cp] = 1;
- }
- /* 改栈顶为akm(m - 1, n + 1),当m = 0时 */
- cp--;
- m1[cp] = m1[cp] - 1;
- n1[cp] = n1[cp + 1] + 1;
- } while (cp >; 0 || m1[cp] >; 0);
-
- return n1[0] + 1;
- }

- g(m, n) = 0 (m = 0, n >;= 0)
- = g(m - 1, 2n) + n; (m >; 0, n >;= 0)
- int g_recursive(int m, int n)
- {
- if (m == 0 && n >;= 0)
- return 0;
- return (g_recurse(m - 1, 2*n) + n);
- }
- int g_nonrecursive(int m, int n)
- {
- int p;
-
- for (p = 0; m >; 0 && n >;= 0; m--, n *= 2)
- p += n;
-
- return p;
- }
- f(n) = n + 1 (n = 0)
- n * f(n/2) (n >; 0)
- int f_recursive(int n)
- {
- if (n == 0)
- return 1;
- return (n * f_recurse(n/2));
- }
- int f_nonrecursive(int n)
- {
- int m;
-
- for (m = 1; n >; 0; n /= 2)
- m *= n;
-
- return m++;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。