基于栈的递归消除
递归操作隐式地调用系统栈,使时间和空间性能有比较大的损耗。我们可以根据自己的需要调用合适的栈结构,从而提高效率。
以中序遍历为例:
void InOrderTraverse(BiTree root) {
InitStack(&s); //初始化栈s
p=root;
while( p!=NULL || !IsEmpty(s) ) { //当前访问节点存在或栈不空
if(p!=NULL) { //当前节点存在
Push(&s,p); //把当前节点压入栈顶
p=p->LChild; //继续遍历左子树
}
else { //当前节点不存在,回溯
Pop(&s,&p); //将栈顶赋给p,出栈
Visit(p->data); //访问节点p
p=p->RChild; //转而访问右子树
}
}
}
二叉树的层序遍历 借助队列结构,先把根节点入队,如果队列不为空,则让队首节点出队,访问该节点并把它的左右孩子分别入队列,然后再出队,再访问,再左右孩子入队,直到队列为空。这样在遍历过程中,是以树的深度为顺序的。
void Traverse(BiTree root) {
if(root!=null)
EnQueue(&q,root); //根节点入队
while(!IsEmpty(q)) {
BiTree temp = DeQueue(&q); //出队
Visite(temp); //访问出队节点
if(temp->LChild)
EnQueue(&q,temp->LChild); //出队节点左孩子入队
if(temp->RChild)
EnQueue(&q,temp->RChild); //出队节点右孩子入队
}
}
二叉树的遍历:前序,中序,后序,层序--包括递归和非递归实现
后序遍历还没有明白,继续学习^_^,过几天写个huffman编码的例子来玩玩,不多说了,看代码吧,注意:程序申请的空间并没有释放^_^
/**/ /* *******************************************************************
created: 2005/12/30
created: 30:12:2005 10:39
filename: bintree.h
author: Liu Qi
purpose: 二叉树的3种遍历方式(包括非递归实现),前序,后序和中序,先访问根节点就是
前序(部分书籍称为先根遍历,个人觉得该说法更好^_^),类似的,最后访问根节点就是后序
******************************************************************** */
#ifndef TREE_H
#define TREE_H
#include < stdio.h >
#include < malloc.h >
#include < stack >
#include < queue >
#include < assert.h >
using namespace std;
typedef int ElemType;
typedef struct treeT
{
ElemType key;
struct treeT * left;
struct treeT * right;
} treeT, * pTreeT;
/**/ /* ===========================================================================
* Function name: visit
* Parameter: root:树根节点指针
* Precondition:
* Description:
* Return value:
* Author: Liu Qi, //-
=========================================================================== */
static void visit(pTreeT root)
{
if (NULL != root)
{
printf( " %d/n " , root -> key);
}
}
/**/ /* ===========================================================================
* Function name: BT_MakeNode
* Parameter: target:元素值
* Precondition: None
* Postcondition: NULL != pTreeT
* Description: 构造一个tree节点,置左右指针为空,并且返回指向新节点的指针
* Return value: 指向新节点的指针
* Author: Liu Qi, [12/30/2005]
=========================================================================== */
static pTreeT BT_MakeNode(ElemType target)
{
pTreeT pNode = (pTreeT) malloc( sizeof (treeT));
assert( NULL != pNode );
pNode -> key = target;
pNode -> left = NULL;
pNode -> right = NULL;
return pNode;
}
/**/ /* ===========================================================================
* Function name: BT_Insert
* Parameter: target:要插入的元素值, pNode:指向某一个节点的指针
* Precondition: NULL != ppTree
* Description: 插入target到pNode的后面
* Return value: 指向新节点的指针
* Author: Liu Qi, [12/29/2005]
=========================================================================== */
pTreeT BT_Insert(ElemType target, pTreeT * ppTree)
{
pTreeT Node;
assert( NULL != ppTree );
Node = * ppTree;
if (NULL == Node)
{
return * ppTree = BT_MakeNode(target);
}
if (Node -> key == target) // 不允许出现相同的元素
{
return NULL;
}
else if (Node -> key > target) // 向左
{
return BT_Insert(target, & Node -> left);
}
else
{
return BT_Insert(target, & Node -> right);
}
}
/**/ /* ===========================================================================
* Function name: BT_PreOrder
* Parameter: root:树根节点指针
* Precondition: None
* Description: 前序遍历
* Return value: void
* Author: Liu Qi, [12/29/2005]
=========================================================================== */
void BT_PreOrder(pTreeT root)
{
if (NULL != root)
{
visit(root);
BT_PreOrder(root -> left);
BT_PreOrder(root -> right);
}
}
/**/ /* ===========================================================================
* Function name: BT_PreOrderNoRec
* Parameter: root:树根节点指针
* Precondition: Node
* Description: 前序(先根)遍历非递归算法
* Return value: void
* Author: Liu Qi, [1/1/2006]
=========================================================================== */
void BT_PreOrderNoRec(pTreeT root)
{
stack < treeT *> s;
while ((NULL != root) || ! s.empty())
{
if (NULL != root)
{
visit(root);
s.push(root);
root = root -> left;
}
else
{
root = s.top();
s.pop();
root = root -> right;
}
}
}
/**/ /* ===========================================================================
* Function name: BT_InOrder
* Parameter: root:树根节点指针
* Precondition: None
* Description: 中序遍历
* Return value: void
* Author: Liu Qi, [12/30/2005]
=========================================================================== */
void BT_InOrder(pTreeT root)
{
if (NULL != root)
{
BT_InOrder(root -> left);
visit(root);
BT_InOrder(root -> right);
}
}
/**/ /* ===========================================================================
* Function name: BT_InOrderNoRec
* Parameter: root:树根节点指针
* Precondition: None
* Description: 中序遍历,非递归算法
* Return value: void
* Author: Liu Qi, [1/1/2006]
=========================================================================== */
void BT_InOrderNoRec(pTreeT root)
{
stack < treeT *> s;
while ((NULL != root) || ! s.empty())
{
if (NULL != root)
{
s.push(root);
root = root -> left;
}
else
{
root = s.top();
visit(root);
s.pop();
root = root -> right;
}
}
}
/**/ /* ===========================================================================
* Function name: BT_PostOrder
* Parameter: root:树根节点指针
* Precondition: None
* Description: 后序遍历
* Return value: void
* Author: Liu Qi, [12/30/2005]
=========================================================================== */
void BT_PostOrder(pTreeT root)
{
if (NULL != root)
{
BT_PostOrder(root -> left);
BT_PostOrder(root -> right);
visit(root);
}
}
/**/ /* ===========================================================================
* Function name: BT_PostOrderNoRec
* Parameter: root:树根节点指针
* Precondition: None
* Description: 后序遍历,非递归算法
* Return value: void
* Author: Liu Qi, // [1/1/2006]
=========================================================================== */
void BT_PostOrderNoRec(pTreeT root)
{
// 学习中,尚未明白
}
/**/ /* ===========================================================================
* Function name: BT_LevelOrder
* Parameter: root:树根节点指针
* Precondition: NULL != root
* Description: 层序遍历
* Return value: void
* Author: Liu Qi, [1/1/2006]
=========================================================================== */
void BT_LevelOrder(pTreeT root)
{
queue < treeT *> q;
treeT * treePtr;
assert( NULL != root );
q.push(root);
while ( ! q.empty())
{
treePtr = q.front();
q.pop();
visit(treePtr);
if (NULL != treePtr -> left)
{
q.push(treePtr -> left);
}
if (NULL != treePtr -> right)
{
q.push(treePtr -> right);
}
}
}
#endif
测试代码
#include < stdio.h >
#include < stdlib.h >
#include < time.h >
#include " tree.h "
#define MAX_CNT 5
#define BASE 100
int main( int argc, char * argv[])
{
int i;
pTreeT root = NULL;
srand( (unsigned)time( NULL ) );
for (i = 0 ; i < MAX_CNT; i ++ )
{
BT_Insert(rand() % BASE, & root);
}
// 前序
printf( " PreOrder:/n " );
BT_PreOrder(root);
printf( " /n " );
printf( " PreOrder no recursion:/n " );
BT_PreOrderNoRec(root);
printf( " /n " );
// 中序
printf( " InOrder:/n " );
BT_InOrder(root);
printf( " /n " );
printf( " InOrder no recursion:/n " );
BT_InOrderNoRec(root);
printf( " /n " );
// 后序
printf( " PostOrder:/n " );
BT_PostOrder(root);
printf( " /n " );
// 层序
printf( " LevelOrder:/n " );
BT_LevelOrder(root);
printf( " /n " );
return 0 ;
}
如果有兴趣不妨运行一下,看看效果^_^
另外请教怎样让二叉树漂亮的输出,即按照树的形状输出
二叉树是很有用的一种数据结构,遍历则是其基本操作,这里列出实是保证完整性。二叉树后序遍历的非递归遍历中当当前节点存在右子树的时候需要先遍历右子树,因此要对二叉树的节点定义中添加_tag域,标志当前节点右子树是否已经遍历,备用的结构定义和函数:
//二叉树节点定义 class TreeNodeElement { public: TreeNodeElement();
TreeNodeElement(int value);
TreeNodeElement(int value,TreeNodeElement* l,TreeNodeElement* r);
~TreeNodeElement();
private: public: int _value;
TreeNodeElement* _l;
TreeNodeElement* _r;
bool _tag; };
typedef TreeNodeElement* TreeNode; |
//构造函数的定义,前序和中序中相似,只是不学要_tag域 TreeNodeElement::TreeNodeElement() { _value = -1;
_l = NULL;
_r = NULL;
_tag = false; }
TreeNodeElement::TreeNodeElement(int value) { _value = value;
_l = NULL;
_r = NULL;
_tag = false; }
TreeNodeElement::TreeNodeElement(int value,TreeNodeElement* l,TreeNodeElement* r) { _value = value;
_l = l;
_r = r;
_tag = false; }
TreeNodeElement::~TreeNodeElement() { delete _l; delete _r; } |
//递归实现(visit) void Visit(TreeNode node) { cout<<node->_value<<" "; } |
二叉树后序遍历的递归和非递归实现:
//递归遍历 void PostRetriveATree(TreeNode root,void (* visit)(TreeNode)) { if (root) { PostRetriveATree(root->_l,visit); PostRetriveATree(root->_r,visit); (*visit)(root); } } |
//非递归遍历,添加#include <stack> void PostRetriveATreeWithoutRecurve(TreeNode root,void (* visit)(TreeNode)) { stack<TreeNode> tree;
while ((root != NULL) || (!tree.empty())) { while (root != NULL) { tree.push(root);
root = root->_l; }
if (!tree.empty()) { root = tree.top();
if (root->_tag) //可以访问 { visit(root);
tree.pop();
root = NULL; //第二次访问标志其右子树也已经遍历 } else { root->_tag = true; root = root->_r; } } } } |