1. 程式人生 > >二叉樹的先序、中序、後序遞歸與非遞歸實現遍歷

二叉樹的先序、中序、後序遞歸與非遞歸實現遍歷

中序遍歷 while循環 節點 非遞歸遍歷 stack left reorder push 後序

//定義二叉樹結點
struct BiTreeNode
{
    int data;
    BiTreeNode* left;
    BiTreeNode* right;      
};

一、遞歸實現

//先序
void preOrder(BiTreeNode *root){
    cout<<root->data;
    preOrder(root->left);
    preOder(root->right);
}

//中序
void inOrder(BiTreeNode *root){
    preOrder(root->left);
    cout
<<root->data; preOder(root->right); } //後序 void postOrder(BiTreeNode *root){ preOrder(root->left); preOder(root->right); cout<<root->data; }

以上的cout<<root->data;是對結點的一種操作,這裏可以對結點做任意想做的操作。

二、非遞歸實現

//先序
void preOrderS(Node *root)   
{
    stack<Node*> s;
    Node 
*p=root; while(p!=NULL||!s.empty()) { //沿著左支走到底 //用棧記錄走過的路徑 while(p!=NULL) { cout<<p->data<<" "; s.push(p); p=p->left; } //當左支走到盡頭時,若棧裏邊還有結點 //則退棧,後退到跟結點,並且向右支前進 //此時p!=NULL,會進入以上while循環
if(!s.empty()) { p=s.top(); s.pop(); p=p->right; } } } //註:在 if(!s.empty())中,獲取根結點只是為了得到往右支的中轉, //當獲得右支指針後,將根結點從棧中彈出,以便返回的時候直接 //回到爺爺結點 //中序 void inOrderS(Node *root){ stack<Node*> s; Node *p=root; while(p!=NULL||!s.empty()){ while(p!=NULL)){ s.push(p); p=p->left; } if(!s.empty()){ p=s.top(); s.pop(); cout<<p->data; p=p->right; } } } //中序遍歷和先序遍歷的代碼幾乎一致,除了訪問點的位置不一樣 //中序遍歷是在退棧的時候訪問根結點
//後序 void PostOrderS(Node *root) { Node *p = root, *r = NULL; stack<Node*> s; while (p!=NULL || !s.empty()) { if (p!=NULL) {//走到最左邊 s.push(p); p = p->left; } else { p = s.top(); if (p->right!=NULL && p->right != r)//右子樹存在,未被訪問 p = p->right; else { s.pop(); visit(p->val); r = p;//記錄最近訪問過的節點 p = NULL;//節點訪問完後,重置p指針 } }//else }//while } //因為後序非遞歸遍歷二叉樹的順序是先訪問左子樹,再訪問右子樹,最後訪問根節點。當用
//堆棧來存儲節點,必須分清返回根節點時,是從左子樹返回的,還從右子樹返回的。所以,
//使用輔助指針r,其指向最近訪問過的節點。也可以在節點中增加一個標誌域,記錄是否已被
//訪問

二叉樹的先序、中序、後序遞歸與非遞歸實現遍歷