二叉樹的遞歸與非遞歸遍歷實現

參閱資料:http://blog.csdn.net/ns_code/article/details/12977901
二叉樹是很常見的數據結構, 它的遍歷方式有遞歸和非遞歸兩種,其中遞歸方式易於實現,而非遞歸的方式往往效率更高,耗資源更少,各有千秋,下面就來介紹下具體的實現方法。

節點結構:

typedef struct Node{
    int val;
    Node* left;
    Node* right;
    Node(int val) : val(val), left(NULL), right(NULL) {}
} *pNode;

先序遍歷:

遞歸方式:
首先遍歷其根結點,然後遍歷左子樹,最後遍歷右子樹,對於其子樹的遍歷方式同上。

void BST::Recursion_preOrder_Traverse(pNode node){
    if(node){
        printf("%d ", node->val);
        Recursion_preOrder_Traverse(node->left);
        Recursion_preOrder_Traverse(node->right);
    }
}

非遞歸方式:
無非就是模擬遞歸,這裏我們用棧模擬。
首先設置一個當前指針curNode,用於指向當前需要操作的節點。
1:對於一個節點,我們輸出它的值,將其入棧,並判斷左子樹是否爲空
2:如果不爲空,那麼curNode指向它,重複1
3:如果爲空,說明此時左子樹已經遍歷完畢,並令當前節點出棧,因爲已經遍歷過了,令curNode指向當前節點的右節點,判斷curNode是否爲空。
4:如果不爲空,重複1
5:如果爲空,說明其沒有右子樹,繼續出棧,重複4、5
6:如果當前curNode爲空並且棧爲空,則遍歷完畢。

void BST::Non_Recursion_preOrder_Traverse(pNode root){
    stack<pNode> pNode_stack;
    pNode curNode = root;
    while(curNode != NULL || !pNode_stack.empty()){
        printf("%d ", curNode->val);
        pNode_stack.push(curNode);
        curNode = curNode->left;
        while(!curNode && !pNode_stack.empty()){//當指針爲空並且棧內有元素時,就可以取出來遍歷右子樹了
            curNode = pNode_stack.top();
            pNode_stack.pop();
            curNode = curNode->right;
        }
    }
}

中序遍歷:

遞歸方式:
首先遍歷其左子樹,然後輸出自己的值,最後遍歷右子樹,對於其子樹的遍歷方式同上。

void BST::Recursion_inOrder_Traverse(pNode node){
    if(node){
        Recursion_inOrder_Traverse(node->left);
        printf("%d ", node->val);
        Recursion_inOrder_Traverse(node->right);
    }
}

非遞歸方式:
1:若當前節點左子樹不爲空,則將該節點入棧,重複1
2:若當前節點左子樹爲空,則輸出其值(注意這裏並沒有將該節點入棧),curNode指向它的右子樹,判斷是否爲空
3:若不爲空,則重複1、2
4:若爲空,則將棧頂元素取出,輸出其值,curNode指向它的右子樹,判斷其是否爲空,重複3、4
5:如果當前curNode爲空並且棧爲空,則遍歷完畢。

void BST::Non_Recursion_inOrder_Traverse(pNode root){
    stack<pNode> pNode_stack;
    pNode curNode = root;
    while(curNode != NULL || !pNode_stack.empty()){
        if(curNode->left != NULL){
            pNode_stack.push(curNode);
            curNode = curNode->left;
        }
        else{
            printf("%d ", curNode->val);
            curNode = curNode->right;
            while(!curNode && !pNode_stack.empty()){
                //此時curNode的左子樹全部遍歷完畢,輸出自己
                curNode = pNode_stack.top();
                printf("%d ", curNode->val);
                pNode_stack.pop();
                curNode = curNode->right;
            }
        }
    }
}

後序遍歷:

遞歸方式:
首先遍歷左子樹,然後遍歷右子樹,最後輸出自己,對於其子樹的遍歷方式同上。

void BST::Recursion_postOrder_Traverse(pNode node){
    if(node){
        Recursion_postOrder_Traverse(node->left);
        Recursion_postOrder_Traverse(node->right);
        printf("%d ", node->val);
    }
}

非遞歸方式:
這裏要多加一個記錄上一個訪問節點的preNode
1:首先將節點入棧
2:如果單籤節點是葉子節點或者它的左右孩子已經有輸出的了,則將其直接輸出並出棧,將棧頂節點設爲curNode並將出棧節點設爲preNode
3:若2不滿足,則將該節點的右孩子和左孩子依次入棧,重複2
4:若棧爲空,則遍歷結束。

void BST::Non_Recursion_postOrder_Traverse(pNode root){
    stack<pNode> pNode_stack;
    pNode curNode = root;
    pNode preNode = NULL;
    pNode_stack.push(curNode);
    while(!pNode_stack.empty()){
        curNode = pNode_stack.top();
        if((curNode->left == NULL && curNode->right == NULL) ||
            (preNode != NULL && (curNode->left == preNode || curNode->right == preNode))){
            printf("%d ", curNode->val);
            pNode_stack.pop();
            preNode = curNode;
        }
        else{
            if(curNode->right != NULL)
                pNode_stack.push(curNode->right);
            if(curNode->left != NULL)
                pNode_stack.push(curNode->left);
        }
    }
}

程序總覽:

#include <cstdio>
#include <stack>
using namespace std;

typedef struct Node{
    int val;
    Node* left;
    Node* right;
    Node(int val) : val(val), left(NULL), right(NULL) {}
} *pNode;

class BST{
private:
    pNode root;

    void Non_Recursion_Insert_Node(pNode *root, int x);
    void Non_Recursion_postOrder_Traverse(pNode root);
    void Recursion_postOrder_Traverse(pNode node);
    void Non_Recursion_inOrder_Traverse(pNode root);
    void Recursion_inOrder_Traverse(pNode root);
    void Recursion_Delete_BST(pNode node);
    void Non_Recursion_preOrder_Traverse(pNode root);
    void Recursion_preOrder_Traverse(pNode node);
public:
    void Non_Recursion_Insert_Node(int x);
    void Non_Recursion_postOrder_Traverse();
    void Recursion_postOrder_Traverse();
    void Non_Recursion_inOrder_Traverse();
    void Recursion_inOrder_Traverse();
    void Non_Recursion_preOrder_Traverse();
    void Recursion_preOrder_Traverse();
    void Build_BST(int *num, int n);
    BST();
    ~BST();
};

void BST::Build_BST(int *num, int n){
    for(int i = 0; i < n; i++){
        Non_Recursion_Insert_Node(&this->root, num[i]);
    }
}

void BST::Non_Recursion_Insert_Node(int x){
    Non_Recursion_Insert_Node(&this->root, x);
}

void BST::Non_Recursion_Insert_Node(pNode *root, int x){
    pNode child = *root;
    pNode parent = NULL;
    while(child != NULL){
        parent = child;
        if(child->val > x){
            child = child->left;
        }
        else{
            child = child->right;
        }
    }
    if(parent == NULL){
        *root = new Node(x);
    }
    else if(parent->val > x){
        parent->left = new Node(x);
    }
    else{
        parent->right = new Node(x);
    }
}

void BST::Non_Recursion_preOrder_Traverse(){
    Non_Recursion_preOrder_Traverse(this->root);
}

void BST::Non_Recursion_preOrder_Traverse(pNode root){
    stack<pNode> pNode_stack;
    pNode curNode = root;
    while(curNode != NULL || !pNode_stack.empty()){
        printf("%d ", curNode->val);
        pNode_stack.push(curNode);
        curNode = curNode->left;
        while(!curNode && !pNode_stack.empty()){//當指針爲空並且棧內有元素時,就可以取出來遍歷右子樹了
            curNode = pNode_stack.top();
            pNode_stack.pop();
            curNode = curNode->right;
        }
    }
}

void BST::Recursion_preOrder_Traverse(pNode node){
    if(node){
        printf("%d ", node->val);
        Recursion_preOrder_Traverse(node->left);
        Recursion_preOrder_Traverse(node->right);
    }
}

void BST::Recursion_preOrder_Traverse(){
    Recursion_preOrder_Traverse(this->root);
}

void BST::Non_Recursion_inOrder_Traverse(){
    Non_Recursion_inOrder_Traverse(this->root);
}

void BST::Non_Recursion_inOrder_Traverse(pNode root){
    stack<pNode> pNode_stack;
    pNode curNode = root;
    while(curNode != NULL || !pNode_stack.empty()){
        if(curNode->left != NULL){
            pNode_stack.push(curNode);
            curNode = curNode->left;
        }
        else{
            printf("%d ", curNode->val);
            curNode = curNode->right;
            while(!curNode && !pNode_stack.empty()){
                //此時curNode的左子樹全部遍歷完畢,輸出自己
                curNode = pNode_stack.top();
                printf("%d ", curNode->val);
                pNode_stack.pop();
                curNode = curNode->right;
            }
        }
    }
}

void BST::Recursion_inOrder_Traverse(pNode node){
    if(node){
        Recursion_inOrder_Traverse(node->left);
        printf("%d ", node->val);
        Recursion_inOrder_Traverse(node->right);
    }
}

void BST::Recursion_inOrder_Traverse(){
    Recursion_inOrder_Traverse(this->root);
}

void BST::Non_Recursion_postOrder_Traverse(){
    Non_Recursion_postOrder_Traverse(this->root);
}

void BST::Non_Recursion_postOrder_Traverse(pNode root){
    stack<pNode> pNode_stack;
    pNode curNode = root;
    pNode preNode = NULL;
    pNode_stack.push(curNode);
    while(!pNode_stack.empty()){
        curNode = pNode_stack.top();
        if((curNode->left == NULL && curNode->right == NULL) ||
            (preNode != NULL && (curNode->left == preNode || curNode->right == preNode))){
            //如果當前節點爲葉子節點或者它的子節點有已經輸出的 那麼就輸出這個節點
            //爲什麼任意左右節點只要有輸出的,該節點就會輸出呢?這是因爲底下的else決定的
            //訪問該節點之前一定會訪問它的左右子節點,如果preNode保存的是它的左節點,那麼
            //一定不存在右節點,當然下一個會訪問他自己,如果perNode保存的是右節點,則說明
            //左節點已經被訪問完畢,這是由入棧順序決定的。
            printf("%d ", curNode->val);
            pNode_stack.pop();
            preNode = curNode;
        }
        else{
            if(curNode->right != NULL)
                pNode_stack.push(curNode->right);
            if(curNode->left != NULL)
                pNode_stack.push(curNode->left);
        }
    }
}

void BST::Recursion_postOrder_Traverse(pNode node){
    if(node){
        Recursion_postOrder_Traverse(node->left);
        Recursion_postOrder_Traverse(node->right);
        printf("%d ", node->val);
    }
}

void BST::Recursion_postOrder_Traverse(){
    Recursion_postOrder_Traverse(this->root);
}

void BST::Recursion_Delete_BST(pNode node){
    if(node == NULL)
        return;
    if(node->left != NULL)
        Recursion_Delete_BST(node->left);
    if(node->right != NULL)
        Recursion_Delete_BST(node->right);
    delete node;
}

BST::BST(){
    root = NULL;
}

BST::~BST(){
    Recursion_Delete_BST(this->root);
}

int main()
{
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章