先序遍历C++实现尾递归

关于尾递归的概念起源于函数式编程,尾递归既可以说是递归,因为从代码结构上看确实是使用到栈,只是栈的开销为常数。尾递归又可以说不是递归,因为这样的递归可以很容易被编译器优化为循环形式,消除栈的调用。在网上常常看到尾递归是不是递归的争论,其实只是编译器帮我们做了非递归的转化而已。

百度百科搜索尾递归的概念,直接使用一个斐波那契数列作为例子,函数状态保存在参数中,而不是传统的栈中,因此不存在栈溢出的危险。但是那个例子比较简单,如下:
long TailRescuvie(long n, long a) {
return(n == 1) ? a : TailRescuvie(n - 1, a * n);
}
long TailRescuvie(long n) {
//封装用的
return(n == 0) ? 1 : TailRescuvie(n, 1);
}
 
但是如果你想用c++语言实现一个先序遍历树的尾递归代码,可能就不那么容易了。在网上搜索了一会儿,可以看到很多函数式编程语言如Lisp、F#的尾递归版本,但是丝毫找不到关于C++的版本,一时间似乎觉得尾递归是函数式编程的专利,c++实现不了。
 
但是仔细思考了一下,编程语言索然千差万别,但是都是图灵等价的,并且Lisp使用C语言实现的,没有理由Lisp可以,C++不可以。所以仔细查看了Lisp的实现,顿然觉得不过如此,C++完全可以实现,其中关键就是需要对函数式编程的惰性计算要有一定的认识,但惰性计算不是函数式编程的专利,C++、Java之类的语言也可以实现的,最关键的是编程的思想,而不是具体的语言,这点Lisp给我很大启发,在最后我也给出了CommonLisp的实现版本,希望把两种不同的语言做个简单对比,从中可以看出Lisp的强大,也许Lisp很古老了,但其中的编程思想(if语句,垃圾回收等)被以后大多语言所继承,一些特性被部分语言支持(代码块),还有一些是其独有的(宏),希望今后的语言可是实现类似Lisp宏的功能(实在太强大啦)。
 
以下给出我的实现代码,希望能对大家尾递归的概念有更深刻的认识。
 
// Node.h,定义了树的节点与惰性计算类
template <class T>
class Node
{
public:
T data;
Node<T>* left;
Node<T>* right;
Node(T data, Node<T>* left, Node<T>* right)
{
this->data=data;
this->left=left;
this->right=right;
}
Node()
{
left=right=NULL;
}
};


template <class T>
class LazyCompute
{
typedef void (*FUN)(Node<T>*,LazyCompute<T>*);
public:
FUN fun;
Node<T>* node;
LazyCompute* compute;
LazyCompute(FUN fun, Node<T>* node, LazyCompute* compute)
{
this->fun=fun;
this->node=node;
this->compute=compute;
}
LazyCompute()
{
}
void computeFun()
{
if(compute)
return fun(node,compute);
}


};
// // Tail recursion.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include "Node.h"




void preorder_aux(Node<int>* node, LazyCompute<int>* lazyCompute)
{
if(node==NULL)
return;
printf("%d\n",node->data);
if(node->left==NULL&&node->right==NULL)
lazyCompute->computeFun();
else
{
preorder_aux(node->left,
new LazyCompute<int>(preorder_aux, node->right, lazyCompute));
}
}


void preorder(Node<int>* tree)
{
return  preorder_aux(tree,new LazyCompute<int>(preorder_aux, NULL, NULL));
}


int _tmain(int argc, _TCHAR* argv[])
{
Node<int>* leftRootLeaf1=new Node<int>(1,NULL,NULL);
Node<int>* leftRootLeaf2=new Node<int>(2,NULL,NULL);
Node<int>* rightRootLeaf1=new Node<int>(3,NULL,NULL);
Node<int>* rightRootLeaf2=new Node<int>(4,NULL,NULL);
Node<int>* leftRoot=new Node<int>(5,leftRootLeaf1,leftRootLeaf2);
Node<int>* rightRoot=new Node<int>(6,rightRootLeaf1,rightRootLeaf2);
Node<int>* root=new Node<int>(0,leftRoot,rightRoot);
preorder(root);
getchar();
return 0;
}
 
Common Lisp的实现
(defmacro lazy(expr)
  `(lambda () ,expr))


(defmacro force(&body body)
  `(funcall ,@body))


(defun bin-tree-leaf-p (B)
  "Test if binary tree B is a leaf."
  (and (listp B) (= (list-length B) 1)))


(defun bin-tree-node-p (B)
  "Test if binary tree B is a node."
  (and (listp B) (= (list-length B) 3)))


(defun make-bin-tree-leaf (E)
  "Create a leaf."
  (list E))


(defun make-bin-tree-node (E B1 B2)
  "Create a node with element K, left subtree B1 and right subtree B2."
  (list E B1 B2))


(defun bin-tree-leaf-element (L)
  "Retrieve the element of a leaf L."
  (first L))


(defun bin-tree-node-element (N)
  "Retrieve the element of a node N."
  (first N))


(defun bin-tree-node-left (N)
  "Retrieve the left subtree of a node N."
  (second N))


(defun bin-tree-node-right (N)
  "Retrieve the right subtree of a node N."
  (third N))


(defun preorder-aux (B A)
  "Append A to the end of the list containing elements of B in preorder."
  (progn 
    (format t "~a~%" (first B))
    (if (bin-tree-leaf-p B)
(force A)
(let
    ((elmt  (bin-tree-node-element B))
     (left  (bin-tree-node-left    B))
     (right (bin-tree-node-right   B)))
  (preorder-aux left
(lazy (preorder-aux right A)))))))


(defun fast-bin-tree-preorder (B)
  "A tail-recursive version of bin-tree-preorder."
  (preorder-aux B (lazy nil)))

 

posted @ 2013-03-21 22:28  gangdelian  阅读(271)  评论(0编辑  收藏  举报