二叉樹的遍歷 C++模板+封裝
阿新 • • 發佈:2019-02-02
二叉樹的遍歷主要是前序、中序和後序遍歷(還有層序遍歷,參見:層序遍歷)
(一)遞迴形式
這三種遍歷訪問順序分別為:
前序:根->左子樹->右子樹
中序:左子樹->根->右子樹
後序:左子樹->右子樹->根
遞迴的形式來寫非常簡單,虛擬碼如下:
//前序遍歷
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;
}