二叉樹各種遍歷算法(遞歸及非遞歸算法)

遍歷的概念:

所謂遍歷(Traversal)是指沿着某條搜索路線,依次對樹中每個結點均做一次且僅做一次訪問。遍歷是二叉樹上最重要的運算之一,是二叉樹上進行其它運算之基礎。二叉樹上訪問結點所做的操作依賴於具體的應用問題。


遍歷方式:

根據訪問結點操作發生位置命名:

① NLR:前序遍歷(PreorderTraversal亦稱(先序遍歷))

——訪問根結點的操作發生在遍歷其左右子樹之前。

② LNR:中序遍歷(InorderTraversal)

——訪問根結點的操作發生在遍歷其左右子樹之中(間)。

③ LRN:後序遍歷(PostorderTraversal)

——訪問根結點的操作發生在遍歷其左右子樹之後。


完整的代碼(C++):

#include <iostream>
#include <queue>
#include <stack>
#include <utility>
using namespace std;

/***********************************************************************************/
/********************************* 定義接口 ****************************************/
/***********************************************************************************/

//二叉樹節點 
template <typename T>
struct BiTree
{
    T *data;
    BiTree *par, *lChild, *rChild;
};

// 構造一個值爲data_value的樹節點 
template <typename T> BiTree<T>* CreateBiTree(const T &data_value); 

// 銷燬樹 
template <typename T> void destory(BiTree<T> *bT);

// 判斷樹是否爲空 
template <typename T> bool empty(BiTree<T> *bT);

// 計算樹的深度 
template <typename T> int depth(BiTree<T> *bT);

// 把另外一棵樹插入到子樹中 
template <typename T>
BiTree<T>* insert(BiTree<T> *bT, BiTree<T> *newBt, const bool &isLeft);

// 生成值爲value的新節點插入到子樹中 
template <typename T>
BiTree<T>* insert(BiTree<T>* bT, const T &value, const bool &isLeft);

// 獲取樹的根 
template <typename T> BiTree<T>* root(BiTree<T>* bT);

// 查找值爲value的子樹
template <typename T> BiTree<T>* find(BiTree<T>* bT, const T &value);

// 三種遍歷方式(遞歸): 先序、中序、後序 
template <typename T> void beforeOrder_traverse_d(BiTree<T>* bT);
template <typename T> void infixOrder_traverse_d(BiTree<T>* bT);
template <typename T> void afterOrder_traverse_d(BiTree<T>* bT);

// 三種遍歷方式(非遞歸): 先序、中序、後序 
template <typename T> void beforeOrder_traverse(BiTree<T>* bT);
template <typename T> void infixOrder_traverse(BiTree<T>* bT);
template <typename T> void afterOrder_traverse(BiTree<T>* bT);

//層序遍歷 
template <typename T> void layerOrder_traverse(BiTree<T>* bT); 


/***********************************************************************************/
/********************************* 接口實現 ****************************************/
/***********************************************************************************/

template <typename T>
BiTree<T>* CreateBiTree(const T &data_value)
{
    BiTree<T>* bT = new BiTree<T>;
    bT->data = new T(data_value);
    bT->par = bT->lChild = bT->rChild = NULL;
    return bT;
}

template <typename T>
void destory(BiTree<T> *bT)
{
    if(bT){
        destory(bT->lChild);
        destory(bT->rChild);
        delete bT->data;
        delete bT;
    }
}

template <typename T>
bool empty(BiTree<T> *bT)
{
    return bT == NULL;
}

template <typename T>
int depth(BiTree<T> *bT)
{
    if(bT){
        int lDepth = depth(bT->lChild), rDepth = depth(bT->rChild);
        return 1 + (lDepth > rDepth ? lDepth : rDepth);
    }
    else{
        return 0;
    }
}

template <typename T>
BiTree<T>* insert(BiTree<T> *bT, BiTree<T> *newBt, const bool &isLeft)
{
    if(isLeft){
        bT->lChild = newBt;
    }
    else{
        bT->rChild = newBt;
    }
    newBt->par = bT;
    return newBt;
}

template <typename T>
BiTree<T>* insert(BiTree<T>* bT, const T &value, const bool &isLeft)
{
    BiTree<T>* newBt = CreateBiTree(value);
    return insert(bT, newBt, isLeft);
}

template <typename T>
BiTree<T>* root(BiTree<T>* bT)
{
    return bT->par ? root(bT->par) : bT;
}

template <typename T>
BiTree<T>* find(BiTree<T>* bT, const T &value)
{
    if(value == *(bT->data)){
        return bT;
    }

    BiTree<T>* res = NULL;
    if(bT->lChild){
        res = find(bT->lChild, value);
        if(res){
            return res;
        }
    }
    if(bT->rChild){
        res = find(bT->rChild, value);
        if(res){
            return res;
        }
    }

    return res;
}

template <typename T>
void beforeOrder_traverse_d(BiTree<T>* bT)
{
    if(bT){
        cout << *(bT->data) << " ";
        beforeOrder_traverse_d(bT->lChild);
        beforeOrder_traverse_d(bT->rChild);
    }
}

template <typename T>
void infixOrder_traverse_d(BiTree<T>* bT)
{
    if(bT){
        infixOrder_traverse_d(bT->lChild);
        cout << *(bT->data) << " ";
        infixOrder_traverse_d(bT->rChild);
    }
}

template <typename T>
void afterOrder_traverse_d(BiTree<T>* bT)
{
    if(bT){
        afterOrder_traverse_d(bT->lChild);
        afterOrder_traverse_d(bT->rChild);
        cout << *(bT->data) << " ";
    }
}

template <typename T>
void beforeOrder_traverse(BiTree<T>* bT)
{
    stack<BiTree<T>*> st;
    BiTree<T>* t = bT;

    while(t || ! st.empty()){
        if(t){
            cout << *(t->data) << " ";
            st.push(t);
            t = t->lChild;
        }
        else{
            t = st.top();
            st.pop();
            t = t->rChild;
        }
    }
}

template <typename T>
void infixOrder_traverse(BiTree<T>* bT)
{
    stack<BiTree<T>*> st;
    BiTree<T>* t = bT;

    while(t || ! st.empty()){
        if(t){
            st.push(t);
            t = t->lChild;
        }
        else{
            t = st.top();
            st.pop();
            cout << *(t->data) << " ";
            t = t->rChild;
        }
    }
}

template <typename T>
void afterOrder_traverse(BiTree<T>* bT)
{
    stack< pair<char, BiTree<T>*> > st;
    BiTree<T>* t = bT;

    while(t || ! st.empty()){

        // 遍歷左子樹
        while(t){
            st.push( pair<char, BiTree<T>*>('L', t) );
            t = t->lChild;
        }

        // 左右子樹訪問完畢訪問根節點  
        while(! st.empty() && st.top().first == 'R'){
            cout << *(st.top().second->data) << " ";
            st.pop();
        }

        // 遍歷右子樹
        if(! st.empty()){
            st.top().first = 'R';
            t = st.top().second;
            t = t->rChild;
        }
    }
}

template <typename T>
void layerOrder_traverse(BiTree<T>* bT)
{
    queue<BiTree<T>*> que;
    que.push(bT);

    while(! que.empty()){
        BiTree<T>* t = que.front();
        if(t){
            cout << *(t->data) << " ";
            que.push(t->lChild);
            que.push(t->rChild);
        }
        que.pop();
    }
}


/***********************************************************************************/
/***********************************************************************************/
/***********************************************************************************/

int main()
{
    BiTree<int>* bT = CreateBiTree(0);

    auto b1 = insert(bT, 1, true);
    insert(bT, 2, false);
    insert(b1, 3, true);
    insert(b1, 4, false);
    auto b2 = find(bT, 2);
    auto rootT = root(insert(b2, 5, true)); 

    cout << "樹的深度:" << depth(bT) << endl;

    cout << "先序遍歷(遞歸):";
    beforeOrder_traverse_d(rootT);
    cout << endl;

    cout << "中序遍歷(遞歸):";
    infixOrder_traverse_d(rootT);
    cout << endl;

    cout << "後序遍歷(遞歸):";
    afterOrder_traverse_d(rootT);
    cout << endl;

    cout << "先序遍歷(非遞歸):";
    beforeOrder_traverse(rootT);
    cout << endl;

    cout << "中序遍歷(非遞歸):";
    infixOrder_traverse(rootT);
    cout << endl;

    cout << "後序遍歷(非遞歸):";
    afterOrder_traverse(rootT);
    cout << endl;

    cout << "層序遍歷:";
    layerOrder_traverse(bT);
    cout << endl;

    destory(bT);
    return 0;
}

效果圖:

這裏寫圖片描述
(手畫的^_^)

這裏寫圖片描述

2018-8-15 編輯添加:

重新學習數據結構時,發現另外一種二叉樹後序遍歷非遞歸算法,代碼如下:

//後序遍歷二叉樹 
template <typename T>
void afterOrder_traverse(BiTree<T>* bT)
{
    BiTree<T>* t = bT;
    if(t != NULL) {
        stack<BiTree<T>*> s;
        do {
            //將所有最左結點壓棧
            while(t) {
                s.push(t);
                t = t->lChild;
            }

            int flag = true;                     // flag爲true表示當前結點的左孩子爲空或者已被訪問
            BiTree<T>* lastVisit = NULL;         // 上一次訪問的節點 

            while(!s.empty() && flag) {
                t = s.top();                     // 注意:這裏只是獲取棧頂元素,而並沒有出棧
                if(t->rChild == lastVisit) {     // 如果當前結點右孩子爲空,或者已經被訪問過,則訪問當前結點
                    s.pop();                     // 當前結點出棧
                    cout << *(t->data) << " ";   // 訪問節點 
                    lastVisit = t;               // 指針變量指向當前結點
                } else {                         // 如果當前結點右孩子不爲空,則先去處理右孩子
                    t = t->rChild;               // 處理右孩子
                    flag = false;                // t的左孩子未被訪問,flag置爲false
                    //lastVisit = t;             // 可省略 
                }
            }
        } while(!s.empty());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章