1. 程式人生 > >二叉樹的遍歷 C++模板+封裝

二叉樹的遍歷 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;
}
這裡寫圖片描述

(四)參考