二叉樹遍歷圖解示意圖可以參考《大話數據結構》P175,看了這個過程能更好的理解算法,作者博客地址:http://cj723.cnblogs.com/
圖一:
前序遍歷:abc
中序遍歷:bac
后序遍歷:bca
|
圖二:
前序遍歷:ABCDEF
中序遍歷:CBAEDF
后序遍歷:CBEFDA
|
#include<iostream>
#include<stack>
using namespace std;
typedef struct BinaryTree
{
char data;
struct BinaryTree* lchild;
struct BinaryTree* rchild;
}binaryTreeNode,*pBinaryTree;
int createBinaryTree(pBinaryTree& root);
//非遞歸實現前序遍歷,利用棧來模擬遞歸過程
void preorderTraversalNonRecursion(pBinaryTree root);
//非遞歸實現中序遍歷,利用棧來模擬遞歸過程
void inorderTraversalNonRecursion(pBinaryTree root);
//非遞歸實現后序遍歷,利用棧來模擬遞歸過程
void postorderTraversalNonRecursion(pBinaryTree root);
int createBinaryTree(pBinaryTree& root)
{
char data;
if(cin>>data)
{
if('#'==data) //輸入#表示該結點為空
{
root = NULL;
return -1;
//只要當輸入是#才會返回-1,表示空樹
}
//建立根結點
binaryTreeNode* node = new binaryTreeNode();
node->data = data;
root = node;
//遞歸去建立左子樹
createBinaryTree(root->lchild);
//遞歸去建立右子樹
createBinaryTree(root->rchild);
}
return 0;
//最終遞歸返回的是0;
}
void preorderTraversalNonRecursion(pBinaryTree root)
{
//訪問節點順序是:根結點,左子樹,右子樹;針對左右子樹,又是按照根左右的順序訪問,所有這個過程中要記錄根結點
if(nullptr==root)
return;
stack<binaryTreeNode*> rootNode;
//遍歷過程中記錄根結點
while(!rootNode.empty()||
nullptr!=root)
{
while(nullptr!=root)
{
cout<<root->data<<" ";
//輸出根結點
//遍歷左子樹
rootNode.push(root);
//記錄左子樹的根結點,前序遍歷回溯訪問右子樹的時候要用到
root = root->lchild;
}
/
/一直遍歷到最左邊的最后一個結點,肯定左子樹為空了,出while循環,這時候就要回溯訪問右子樹了
if(!rootNode.empty())
{
root = rootNode.top();
//棧中取出最近入棧的根結點
root = root->rchild;
//根結點指向右子樹
rootNode.pop(); /
/最近壓棧的根結點彈棧
//右子樹也是一棵二叉樹,又回到第二個while循環,前序遍歷,根左右的方法訪問右子樹
}
else
root = NULL;
}
}
void inorderTraversalNonRecursion(pBinaryTree root)
{
//左子樹,根結點,右子樹
if(nullptr==root)
return ;
stack<binaryTreeNode*> rootNode;
while(nullptr!=root||
!rootNode.empty())
{
while(nullptr!=root)
{
rootNode.push(root);
//棧中保存根結點,先去訪問左子樹
root = root->lchild;
}
//左子樹遍歷完畢
cout<<rootNode.top()->data<<" ";
//訪問根結點
root = rootNode.top()->rchild;
//訪問右子樹
rootNode.pop();
//出棧最近保存的結點
}
}
|
typedef struct Traversal
{
binaryTreeNode* rootAddr;
//二叉樹結點地址
bool accessToken;
//訪問標記
}traversalInfo,*pTraversal;
void postorderTraversalNonRecursion(pBinaryTree root)
{
//后序遍歷,左子樹,右子樹,根結點
//遍歷完左子樹后要回溯到根結點去遍歷右子樹,所以需要一個標記來記錄根結點,如果是第二次遍歷到就直接輸出值
if(nullptr==root)
return ;
stack<traversalInfo> rootNodeIndo;
while(nullptr!=root)
//二叉樹根結點最后才會訪問
{
//遍歷左子樹
traversalInfo tmp;
tmp.rootAddr = root;
tmp.accessToken = false;
//第一次訪問,第二次訪問修改為true,輸出信息
rootNodeIndo.push(tmp);
//遍歷右子樹沿途的根結點入棧
root = root->lchild;
}
//開始回溯遍歷右子樹
while(!rootNodeIndo.empty())
{
root = rootNodeIndo.top().rootAddr;
//取出最近訪問的根結點
//遍歷右子樹
while(nullptr!=root->rchild&&
!rootNodeIndo.top().accessToken)
//右子樹不空,並且根結點只存在第一次訪問
{
rootNodeIndo.top().accessToken = true;
//根結點第二次訪問,修改為true,下次回溯訪問到就要輸出
//右子樹根結點進棧
root = root->rchild;
traversalInfo tmp;
tmp.rootAddr = root;
tmp.accessToken = false;
rootNodeIndo.push(tmp);
//右子樹的左子樹不空,接着遍歷左子樹
while(nullptr!=root->lchild)
{
root = root->lchild;
traversalInfo tmp;
tmp.rootAddr = root;
tmp.accessToken = false;
rootNodeIndo.push(tmp);
}
//右子樹的左子樹遍歷完畢,回溯遍歷右子樹的右子樹。
}
//輸出結點信息
//執行下面語句只有兩種情況,1、對應二叉樹最左邊結點沒有右子樹,包括右子樹的最左邊結點
//2、回溯再次訪問到根結點,即第3個while循環的第二個條件!rootNodeIndo.top().accessToken不滿足
cout<<rootNodeIndo.top().rootAddr->data<<" ";
rootNodeIndo.pop();
//出棧
}
}
int main()
{
pBinaryTree root = nullptr;
int ret = createBinaryTree(root);
if(0==ret)
{
cout<<"preorder traversal non-recursion:"<<endl;
preorderTraversalNonRecursion(root);
cout<<endl<<endl;;
cout<<"inorder traversal non-recursion:"<<endl;
inorderTraversalNonRecursion(root);
cout<<endl<<endl;;
cout<<"postorder traversal non-recursion:"<<endl;
postorderTraversalNonRecursion(root);
cout<<endl;
}
cout<<endl;
system("pause");
}
|
//后序遍歷算法優化
typedef struct Traversal
{
binaryTreeNode* rootAddr;
bool accessToken;
}traversalInfo,*pTraversal;
void stackPush(stack<traversalInfo>& rootNodeInfo,binaryTreeNode* &rootAddr,bool&& flag)
{
traversalInfo tmp;
tmp.rootAddr = rootAddr;
tmp.accessToken = flag;
rootNodeInfo.push(tmp);
}
|
void postorderTraversalNonRecursion(pBinaryTree root)
{
if(nullptr==root)
return ;
stack<traversalInfo> rootNodeInfo;
while(nullptr!=root)
{
stackPush(rootNodeInfo,root,false);
root = root->lchild;
}
while(!rootNodeInfo.empty())
{
root = rootNodeInfo.top().rootAddr;
while(nullptr!=root->rchild&&
!rootNodeInfo.top().accessToken)
{
rootNodeInfo.top().accessToken = true;
root = root->rchild;
stackPush(rootNodeInfo,root,false);
while(nullptr!=root->lchild)
{
root = root->lchild;
stackPush(rootNodeInfo,root,false);
}
}
cout<<rootNodeInfo.top().rootAddr->data<<" ";
rootNodeInfo.pop();
}
}
|