二叉树各种遍历算法(递归及非递归算法)

遍历的概念:

所谓遍历(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());
    }
}
展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值