二叉树的遍历 C++模板+封装

二叉树的遍历主要是前序、中序和后序遍历(还有层序遍历,参见:层序遍历

(一)递归形式

这三种遍历访问顺序分别为:

前序:根->左子树->右子树
中序:左子树->根->右子树
后序:左子树->右子树->根

递归的形式来写非常简单,伪代码如下:

//前序遍历
void PreOrder(TreeNode *root)
{
    if (root == NULL)
        return;
    Visit root->val;
    PreOrder(root->left);
    PreOrder(root->right);
}

//中序遍历
void InOrder(TreeNode *root)
{
    if (root == NULL)
        return;
    InOrder(root->left);
    Visit root->val;
    InOrder(root->right);
}

//后序遍历
void PostOrder(TreeNode *root)
{
    if (root == NULL)
        return;
    PostOrder(root->left);
    PostOrder(root->right);
    Visit root->val;
}

(二)非递归形式

非递归形式主要利用栈来实现各种顺序遍历时节点的访问顺序。

2.1非递归先序遍历

1.对于节点P,只要左子树不为空,就一直向左访问,并将访问的节点压栈。
2.当左子树为空时,另P指向栈顶元素的右节点并弹栈,执行步骤1。

void PreOrderNonRescursion(TreeNode *root)//伪代码
{
    NodeType *p=root;
    stack<NodeType*>s;
    while(NULL!=p || !s.empty())
    {
        while(NULL!=p)
        {
            s.push(p);
            visit p->val;
            p=p->left;
        }
        if(!s.empty())
        {
            p=s.top();
            s.pop();
            p=p->right;
        }
    }
}

2.2非递归中序遍历

与先序遍历类似。
1.对于节点P,只要左子树不为空,就一直向左压栈(但不访问)
2.当左子树为空时,访问栈顶元素,并另P指向栈顶元素的右子树,弹栈,执行步骤1。

template <typename T>
void InOrderNonRescursion(TreeNode*root)//伪代码
{
    NodeType *p=root;
    stack<NodeType*>s;
    while(NULL!=p || !s.empty())
    {
        while(NULL!=p)
        {
            s.push(p);
            p=p->left;
        }
        if(!s.empty())
        {
            p=s.top();
            visit p->val
            s.pop();
            p=p->right;
        }
    }
}

2.3非递归后序遍历

这个就相对复杂了。要保证在访问当前节点Cur之前,
1.要么Cur不存在左右孩子,即左右子树为NULL。
2.要么Cur的左右孩子已经被访问过了,Pre节点不为NULL且为Cur节点的左右孩子之一。

否则,如果不满足上述条件,说明当前Cur节点的左右孩子还没有被访问,那么为了保证先左子树在右子树的访问顺序,我们要先将右子树压栈,再将左子树压栈(如果不为空的话。)

结合上述条件有:

void Tree<T>::PostOrderNonRescursion(NodeType*root)//伪代码
{
    NodeType *pre=NULL;
    //NodeType *cur=root;
    NodeType *cur;
    stack<NodeType*>s;
    s.push(root);
    while( !s.empty())
    {
        cur=s.top();
        if( ((cur->left==NULL)&&(cur->right==NULL))|| //左右子树为空
            (pre!=NULL&&(pre==cur->left||pre==cur->right)) )//或者左右子树已被访问
        {
            //visit cur
            s.pop();
            pre=cur;
        }
        else
        {
            if(cur->right!=NULL)
                s.push(cur->right);
            if(cur->left !=NULL)
                s.push(cur->left);
        }
    }
}

(三)二叉树的封装

假期无聊。想了想,就把上述三种遍历递归和非递归形式用模板封装了下。

3.1数据结构

//TreeNode.h

#ifndef __TREENODE_H__
#define __TREENODE_H__
#include "Tree.h"
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
template <typename T> class Tree;
template <typename T>
class TreeNode
{
    friend class Tree<T>;
    private:
        T val;
    public:
        TreeNode<T>*left;
        TreeNode<T>*right;

        TreeNode():val(0),left(NULL),right(NULL){}
        TreeNode(T x):val(x),left(NULL),right(NULL){}
};
#endif

3.2二叉树的封装

#ifndef __TREE_H__
#define __TREE_H__
#include "TreeNode.h"
using namespace std;

template <typename T> class TreeNode;


template  <typename T>
class Tree
{

    typedef TreeNode<T> NodeType;
    private:
        NodeType *root;
        void PreOrder_(NodeType *,vector<T>&);
        void InOrder_(NodeType *,vector<T>&);
        void PostOrder_(NodeType *,vector<T>&);
        void PreOrderNonRescursion_(NodeType *,vector<T>&);
        void InOrderNonRescursion_(NodeType *,vector<T>&);
        void PostOrderNonRescursion_(NodeType *,vector<T>&);
        void DestroyAllNode_(NodeType *);
    public:
        Tree(NodeType * r){root=r;}
        ~Tree();
        void PreOrder(vector<T>&);
        void InOrder(vector<T>&);
        void PostOrder(vector<T>&);
        void PreOrderNonRescursion(vector<T>&);
        void InOrderNonRescursion(vector<T>&);
        void PostOrderNonRescursion(vector<T>&);

};

//constructor and destructor//
template <typename T>
void Tree<T>::DestroyAllNode_(NodeType*root)
{
    if(root==NULL)
        return ;
    DestroyAllNode_(root->left);
    DestroyAllNode_(root->right);
    delete root;
    root=NULL;
    return ;
}

template <typename T>
Tree<T>::~Tree()
{
    DestroyAllNode_(root);
}
/PreOrder Traversal//
template <typename T>
void Tree<T>::PreOrder_(NodeType*root,vector<T>&res)
{
    if(root==NULL)
    {
        return;
    }
    res.push_back(root->val);
    PreOrder_(root->left,res);
    PreOrder_(root->right,res);
}

template <typename T>
void Tree<T>::PreOrder(vector<T>&res)
{
    PreOrder_(root,res);
}

template <typename T>
void Tree<T>::PreOrderNonRescursion_(NodeType*root,vector<T>&res)
{
    NodeType *p=root;
    stack<NodeType*>s;
    while(NULL!=p || !s.empty())
    {
        while(NULL!=p)
        {
            s.push(p);
            res.push_back(p->val);
            p=p->left;
        }
        if(!s.empty())
        {
            p=s.top();
            s.pop();
            p=p->right;
        }
    }
}
template <typename T>
void Tree<T>::PreOrderNonRescursion(vector<T>&res)
{
    PreOrderNonRescursion_(root,res);
}

//InOrder Traversal///
template <typename T>
void Tree<T>::InOrder_(NodeType*root,vector<T>&res)
{
    if(root==NULL)
    {
        return;
    }
    InOrder_(root->left,res);
    res.push_back(root->val);
    InOrder_(root->right,res);
}

template <typename T>
void Tree<T>::InOrder(vector<T>&res)
{
    InOrder_(root,res);
}

template <typename T>
void Tree<T>::InOrderNonRescursion_(NodeType*root,vector<T>&res)
{
    NodeType *p=root;
    stack<NodeType*>s;
    while(NULL!=p || !s.empty())
    {
        while(NULL!=p)
        {
            s.push(p);
            p=p->left;
        }
        if(!s.empty())
        {
            p=s.top();
            res.push_back(p->val);
            s.pop();
            p=p->right;
        }
    }
}
template <typename T>
void Tree<T>::InOrderNonRescursion(vector<T>&res)
{
    InOrderNonRescursion_(root,res);
}

/PostOrder Traversal
template <typename T>
void Tree<T>::PostOrder_(NodeType*root,vector<T>&res)
{
    if(root==NULL)
    {
        return;
    }
    PostOrder_(root->left,res);
    PostOrder_(root->right,res);
    res.push_back(root->val);
}

template <typename T>
void Tree<T>::PostOrder(vector<T>&res)
{
    PostOrder_(root,res);
}

template <typename T>
void Tree<T>::PostOrderNonRescursion_(NodeType*root,vector<T>&res)
{
    NodeType *pre=NULL;
    //NodeType *cur=root;
    NodeType *cur;
    stack<NodeType*>s;
    s.push(root);
    while( !s.empty())
    {
        cur=s.top();
        if( ((cur->left==NULL)&&(cur->right==NULL))||
            (pre!=NULL&&(pre==cur->left||pre==cur->right)) )
        {
            res.push_back(cur->val);
            s.pop();
            pre=cur;
        }
        else
        {
            if(cur->right!=NULL)
            s.push(cur->right);
            if(cur->left !=NULL)
            s.push(cur->left);
        }
    }
}
template <typename T>
void Tree<T>::PostOrderNonRescursion(vector<T>&res)
{
    PostOrderNonRescursion_(root,res);
}

#endif

3.3测试

//main.cpp

#include "Tree.h"
int main()
{
    TreeNode<int> *root=new TreeNode<int>(0);
    root->left=new TreeNode<int>(1);
    root->right=new TreeNode<int>(2);

    Tree<int> t(root);

    vector<int>res;
    t.PreOrder(res);
    for(int i=0;i<res.size();i++)
    {
        cout << res[i];
        cout <<endl;
    }

    res.clear();
    t.PreOrderNonRescursion(res);
    for(int i=0;i<res.size();i++)
    {
        cout << res[i];
        cout <<endl;
    }

    res.clear();
    t.InOrder(res);
    for(int i=0;i<res.size();i++)
    {
        cout << res[i];
        cout <<endl;
    }

    res.clear();
    t.InOrderNonRescursion(res);
    for(int i=0;i<res.size();i++)
    {
        cout << res[i];
        cout <<endl;
    }

    res.clear();
    t.PostOrder(res);
    for(int i=0;i<res.size();i++)
    {
        cout << res[i];
        cout <<endl;
    }

    res.clear();
    t.PostOrderNonRescursion(res);
    for(int i=0;i<res.size();i++)
    {
        cout << res[i];
        cout <<endl;
    }


    return 0;
}

这里写图片描述


(四)参考

1.http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值