版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/credolhcw/article/details/59046393
真的是已经滚瓜烂熟的算法 —— 前序、中序、后序遍历的几种实现
由于每个节点都要访问到,所以树的遍历时间复杂度必然大于O(n),所以优化方式主要是减少空间消耗。然而,我目前没有碰到过需要将空间复杂度控制在O(1)的情况,等有需要的时候再学习这种算法吧……
度为m(m>2)树的遍历
m树的遍历也有前序、中序、后序之分。前序和后序遍历很好理解,和二叉树的概念是一样的。
m树的中序遍历规则:先访问第一个子树,再访问根节点,然后访问其他的子树。
往往m树都会以孩子-兄弟表示法转化为对应的二叉树(BiTree)进行存储,而BiTree的中序遍历结果和m树的中序遍历结果是相同的。
二叉树的遍历
为了方便理解,我分前序、中序、后序三个部分进行复习,并且每个部分都使用递归、父节点指针、栈等三中方法实现。
为了灵活的调用各种Visit函数,我使用了成员函数指针进行函数调用。(参考博客《C++成员函数指针揭秘》:http://blog.csdn.net/icycode/article/details/6758636)
Stack方法使用了STL中的stack库,如果懒得看头文件,可以看看这个博客:http://blog.csdn.net/wallwind/article/details/6858634
另,我自己写的测试程序类的定义放在文章的最后面。
二叉树前序遍历
1. 递归方法
int BiTree::biTreeTravelByRecursionPreOrder( BiTreeNode *btn, pFuncNoReturn pf )
{
(this->*pf)(btn); // 以类成员函数指针的方式调用访问函数
if( btn->lchild != NULL ) {
// 左子树不为空,访问左子树
this->biTreeTravelByRecursionPreOrder(btn->lchild,pf);
}
if( btn->rchild != NULL ) {
// 右子树不为空,访问右子树
this->biTreeTravelByRecursionPreOrder(btn->rchild,pf);
}
return 0;
}
2. 父节点指针方法
int BiTree::biTreeTravelByFatherPointerPreOrder(pFuncNoReturn pf )
{
if( this->isEmpty() ) return 0; // 空树直接返回
BiTreeNode *btn = this->_root; // 遍历指针
/*
* 'i',记录已访问个数
* 'while(i<this->_nodeNum)',全部节点都访问完,则跳出循环
*/
int i = 0;
while( i < this->_nodeNum ) {
/*
* if的语义为“以btn为根的子树还未被访问”
*/
if( !btn->getVisited() ) {
while(1) {
/* 访问根节点 */
(this->*pf)(btn);
btn->setVisited(true);
i++;
/* 访问左子树,直到左子树为空 */
if( btn->lchild != NULL ) btn = btn->lchild;
else break;
}
}
/*
* 前面的循环已经完成了根和左子树的访问
* 若btn的右子树不为空且未被访问则访问右子树
* 否则,即表示btn为根的子树已访问完毕,退回至父节点
*/
if( btn->rchild != NULL && !btn->rchild->getVisited() ) btn = btn->rchild;
else btn = btn->parent;
}
return 0;
}
3. Stack方法
int BiTree::biTreeTravelByStackPreOrder( pFuncNoReturn pf )
{
BtnStack s;
if( this->isEmpty() ) return 0;
BiTreeNode *btn = this->_root;
while(1) {
while( btn != NULL ) {
(this->*pf)(btn); // visit
/* 存在右节点,则将右节点入栈 */
if( btn->rchild != NULL ) s.push(btn->rchild);
btn = btn->lchild;
}
if( s.empty() ) break; // 结束循环
/* 根节点和左子树访问完毕后,将右节点出站继续访问 */
btn = s.top();
s.pop();
}
return 0;
}
二叉树中序遍历
1. 递归方法
int BiTree::biTreeTravelByRecursionInOrder( BiTreeNode *btn, pFuncNoReturn pf )
{
if( btn->lchild != NULL ) {
this->biTreeTravelByRecursionInOrder(btn->lchild,pf);
}
(this->*pf)(btn);
if( btn->rchild != NULL ) {
this->biTreeTravelByRecursionInOrder(btn->rchild,pf);
}
return 0;
}
2. 父节点指针方法
int BiTree::biTreeTravelByFatherPointerInOrder(pFuncNoReturn pf )
{
if( this->isEmpty() ) return 0;
BiTreeNode *btn = this->_root;
int i = 0;
while( i < this->_nodeNum ) {
/* 中序遍历先访问左子树,所以先将btn指向当前子树的最左端 */
while( btn->lchild != NULL && !btn->lchild->getVisited() ) btn = btn->lchild;
/*
* 由于已经将btn移至当前子树的最左端
* 所以相当于访问了子树btn的根节点
*/
if( !btn->getVisited() ) {
(this->*pf)(btn);
btn->setVisited(true);
i++;
}
/*
* 若子树btn存在右节点,则将btn指向右子树的根
* 否则返回至父节点
*/
if( btn->rchild != NULL && !btn->rchild->getVisited() ) btn = btn->rchild;
else btn = btn->parent;
}
return 0;
}
3. Stack方法
int BiTree::biTreeTravelByStackInOrder( pFuncNoReturn pf )
{
BtnStack s;
if( this->isEmpty() ) return 0;
BiTreeNode *btn = this->_root;
while(1) {
while( btn != NULL ) {
s.push(btn); // 根节点入栈
btn = btn->lchild;
}
if( s.empty() ) break;
/* 访问栈顶元素 */
(this->*pf)(s.top()); // visit
/* 若右子树为空,则正好不会进入上面的while循环,从而继续出站操作 */
btn = s.top()->rchild;
s.pop();
}
return 0;
}
二叉树后序遍历
1. 递归方法
int BiTree::biTreeTravelByRecursionPostOrder( BiTreeNode *btn, pFuncNoReturn pf )
{
if( btn->lchild != NULL ) {
this->biTreeTravelByRecursionPostOrder(btn->lchild,pf);
}
if( btn->rchild != NULL ) {
this->biTreeTravelByRecursionPostOrder(btn->rchild,pf);
}
(this->*pf)(btn);
return 0;
}
2. 父节点指针方法
int BiTree::biTreeTravelByFatherPointerPostOrder(pFuncNoReturn pf )
{
if( this->isEmpty() ) return 0;
BiTreeNode *btn = this->_root;
int i = 0;
while( i < this->_nodeNum ) {
while( btn->lchild != NULL && !btn->lchild->getVisited() ) btn = btn->lchild;
if( btn->rchild != NULL && !btn->rchild->getVisited() ) btn = btn->rchild;
else {
/* 访问当前树的最左端或者最下端的节点 */
(this->*pf)(btn);
btn->setVisited(true);
i++;
btn = btn->parent;
}
}
return 0;
}
3. Stack方法
int BiTree::biTreeTravelByStackPostOrder( pFuncNoReturn pf )
{
BtnStack s;
if( this->isEmpty() ) return 0;
BiTreeNode *btn = this->_root;
while(1) {
/*
* 向左遍历
* 将沿路的未访问节点都入栈
* 最左端(未访问)的节点不入栈
*/
while( btn->lchild != NULL && !btn->lchild->getVisited() ) {
s.push(btn);
btn = btn->lchild;
}
/*
* btn指向当前树的最左端(未访问)节点
* 若存在右节点,且未访问,则将btn入栈,将btn指向其右子树根节点,继续循环
* 否则,访问btn
*/
if( btn->rchild != NULL && !btn->rchild->getVisited() ) {
s.push(btn);
btn = btn->rchild;
}
else {
(this->*pf)(btn); // visit
btn->setVisited(true);
if( s.empty() ) break;
btn = s.top();
s.pop();
}
}
return 0;
}
相关定义
二叉树的节点类,BiTreeNode:
class BiTreeNode
{
private:
char _data;
bool _visited; // "true"表示已访问
public:
BiTreeNode *lchild;
BiTreeNode *rchild;
BiTreeNode *parent;
public:
BiTreeNode( char data ) {
this->_data = data;
this->_visited = false;
this->lchild = NULL;
this->rchild = NULL;
this->parent = NULL;
}
public:
char getData() { return this->_data; }
bool getVisited() { return this->_visited; }
void setVisited( bool visited ) { this->_visited = visited; }
void setData( int data ) { this->_data = data; }
};
为Stack定义别名BtnStack(Btn,即 Binary tree node):
typedef std::stack<BiTreeNode*> BtnStack;
二叉树类定义(BiTree),由于不想些一大堆的注释,所以我吧函数名写的有点长( ̄ε  ̄) :
// 为函数指针pFuncNoReturn取别名,所以需要先声明类BiTree
class BiTree;
typedef void (BiTree::*pFuncNoReturn)( BiTreeNode *btn );
class BiTree
{
private:
BiTreeNode *_root; // 二叉树根节点
int _nodeNum; // 二叉树的节点数
public:
BiTreeNode *buff; // 存函数biSearch返回的位置,和本文的内容没关系
BiTree() {
this->_root = NULL;
this->buff = NULL;
this->_nodeNum = 0;
}
public:
bool isEmpty() {
if( this->_nodeNum <= 0 ) return true;
return false;
}
public:
bool biSearch( char target ); // 二分检索target,本文就当做createBiTree用
void biRenew() {
// 用遍历的方式置所有节点的_visited属性为“未访问状态”
this->biTreeTravelByRecursionPreOrder(this->_root,this->renewNodeData);
}
public:
/* pFuncNoReturn */
void printNodeData( BiTreeNode *btn ) { std::cout << btn->getData(); }
void renewNodeData( BiTreeNode *btn ) { btn->setVisited(false); }
private:
/* Travel by recursion type */
int biTreeTravelByRecursionPreOrder( BiTreeNode *btn, pFuncNoReturn pf );
int biTreeTravelByRecursionInOrder( BiTreeNode *btn, pFuncNoReturn pf );
int biTreeTravelByRecursionPostOrder( BiTreeNode *btn, pFuncNoReturn pf );
/* Travel by Pointer */
int biTreeTravelByFatherPointerPreOrder( pFuncNoReturn pf );
int biTreeTravelByFatherPointerInOrder( pFuncNoReturn pf );
int biTreeTravelByFatherPointerPostOrder( pFuncNoReturn pf );
/* Travel by Stack */
int biTreeTravelByStackPreOrder( pFuncNoReturn pf );
int biTreeTravelByStackInOrder( pFuncNoReturn pf );
int biTreeTravelByStackPostOrder( pFuncNoReturn pf );
}