begincsdn .NET 趴趴窝
[天行健,君子以自强不息]
[天道酬勤思]

二叉树的递归遍历以及非递归遍历(一)----先序遍历

1.二叉树的遍历方式:

先序遍历、中序遍历、后序遍历(此处不考虑层次遍历)

先序遍历:先访问根节点,再访问左子树,然后是右子树

中序遍历:先访问左子树,然后是根节点,然后是右子树

后序遍历:先访问左子树,然后右子树,最后是根节点。

2. 二叉树基本数据结构定义:

typedef struct TNode

{

int val;

struct TNode* pLeft;

struct TNode* pRight;

TNode(int val, TNode* pLeft, TNode* pRight)

{

this->val = val;

this->pLeft = pLeft;

this->pRight = pRight;

}

TNode()

{

}

~TNode()

{

if (pLeft)

{

delete pLeft;

pLeft = NULL;

}

if (pRight)

{

delete pRight;

pRight = NULL;

}

}

}TNode;

二叉树的构造:

/**************************************************************************************

4

1 5

2 3 6 7

***************************************************************************************/

TNode* buildTree()

{

TNode *p = new TNode(1,

new TNode(2, NULL,NULL),

new TNode(3, NULL,NULL));

TNode *q = new TNode(4,

p,

new TNode(5,

new TNode(6, NULL,NULL),

new TNode(7, NULL,NULL)));

return q;

};

树的逻辑结构如下:

clip_image002[4]

图一(测试用树结构)

3. 先序遍历

3.1 先序遍历的递归写法:

/**********************************************

功能:递归先序遍历

注:遍历顺序为根左右

**********************************************/

void preTraverse(TNode* pRoot)

{

if (!pRoot) return;

visit(pRoot);

preTraverse(pRoot->pLeft);

preTraverse(pRoot->pRight);

}

3.2 先序遍历的非递归写法:

/**********************************************

功能:非递归先序遍历

住:遍历顺序为根左右

**********************************************/

void preNoRecTraverse(TNode* pRoot)

{

stack<TNode*> s;

TNode* p = pRoot;

s.push(p);

while (p || !s.empty())

{

p = s.top();

s.pop();

visit(p);

if (p->pRight) s.push(p->pRight);

if (p->pLeft) s.push(p->pLeft);

}

}

3.3 过程模拟及结果展示:

递归调用过程:

clip_image003

图二:递归调用的函数调用层次关系

非递归的遍历过程,其实就是模拟递归算法中的堆栈进出顺序。

在递归调用中,可以看到在每一次的递归调用中,总是首先访问根,然后访问左子树,然后访问右子树。对右子树的访问在左子树访问的后面。所以右子树的根先入栈,右子树的根后入栈。

栈的进出图如下:

clip_image005

图三:非递归调用的栈进出图

遍历结果为:(4,1,2,3,5,6,7)

递归算法和非递归算法的比较:

此处把正在运行的函数看成是一个栈,调用其他函数看成是进栈,调用函数运行完认为是出栈,模拟一下递归调用的栈:

clip_image007

共同点:两者对节点的遍历次序一致

区别:在非递归调用中,对右子树的访问在左子树后面,所以先将右子树节点压栈,再压左子树节点,这样在出栈进行遍历的时候起到先遍历左子树,再遍历右子树的效果。
在递归调用中,对左右子树调用的先后区别在于是先调用左子树的遍历函数,再调用右子树的遍历函数,起到的效果是一致的。

posted on 2012-10-12 08:54  begincsdn  阅读(3048)  评论(0编辑  收藏  举报