[C++] 非递归实现前中后序遍历二叉树

网上代码一搜一大片,大同小异咯。
书上的函数实现代码甚至更胜一筹,而且抄一遍就能用,唯一问题是没有写二叉树节点和树的模版类的构造实现,和没有具体实现 visit 函数(也没说明,略坑)。

只需要前中后序遍历的话很多函数都不需要,此外值得吐槽的一点是,明明 BinaryTreeNode 类里面接口写的很明确,私有成员也都保护起来了,最后却把 BinaryTree 添加为了友元类,这波操作着实令人费解。
为了添加这个友元类还需要先进行两个类的声明,之后才能逐个实现,迷了。
但这都不是我按顺序实现了接口函数,最后还是没有调用接口函数的理由。所以根本原因其实就是懒。

前置技能

四种遍历方法分别为:

  • 层次遍历 “ 从上到下,从左到右 ”
  • 前序遍历 “ 根结点 -> 左子树 -> 右子树 ”
  • 中序遍历 “ 左子树 -> 根结点 -> 右子树 ”
  • 后序遍历 “ 左子树 -> 右子树 -> 根结点 ”
图片来自网络

层次遍历使用了队列进行实现,而前中后序遍历是利用的栈来实现。而前序遍历、中序遍历和后序遍历中,后序遍历的实现无疑是最复杂的。

需求描述

直接上头文件,需要注意的是我没有实现建树、删树和插入的函数,顺手还多抄了一个层次遍历的函数。整体来看是一个很菜的代码,只在主函数里随便构了一个二叉树测试遍历函数。
全部都是模版类的实现写起来很麻烦,实现好了很舒服23333
binarytree.h


template<class T>
class BinaryTreeNode;

template<class T>
class BinaryTree;

template<class T>
class BinaryTreeNode{
private:
    T element;                        //数据域
    BinaryTreeNode<T> * leftChild;    //左孩子
    BinaryTreeNode<T> * rightChild;   //右孩子
public:
    BinaryTreeNode();                 //默认构造
    BinaryTreeNode(T& ele);           //给定数据域值的构造
    BinaryTreeNode(T& ele, BinaryTreeNode<T> * l, BinaryTreeNode<T> * r);
    BinaryTreeNode<T> * getLeftChild();           //返回左孩子
    BinaryTreeNode<T> * getRightChild();          //返回右孩子
    bool setLeftChild(BinaryTreeNode<T> * l);     //设置左孩子
    bool setRightChild(BinaryTreeNode<T> * r);    //设置右孩子
    T getValue() const;                           //返回数据值
    bool isLeaf() const;                          //判断是否为叶子节点
    friend class BinaryTree<T>;
};

template<class T>
class BinaryTree{
private:
    BinaryTreeNode<T> * root;  //根节点
public:
    BinaryTree();              //默认构造
    BinaryTree(BinaryTreeNode<T> * r);
    ~BinaryTree();             //析构
    bool isEmpty() const;      //判断是否为空树
    void visit(BinaryTreeNode<T> * pointer);
    BinaryTreeNode<T> * getRoot() const;              //返回根节点
    void preOrder(BinaryTreeNode<T> * root);          //先序遍历
    void inOrder(BinaryTreeNode<T> * root);           //中序遍历
    void postOrder(BinaryTreeNode<T> * root);         //后序遍历
    void levelOrder(BinaryTreeNode<T> * root);        //层次遍历
};

具体实现

binarytree.cpp

#include"binarytree.h"
#include<iostream>
#include<queue>
#include<stack>

template<class T>
BinaryTreeNode<T>::BinaryTreeNode(){
    element = 0;
    leftChild = nullptr;
    rightChild = nullptr;
}

template<class T>
BinaryTreeNode<T>::BinaryTreeNode(T& ele){
    element = ele;
    leftChild = nullptr;
    rightChild = nullptr;
}
template<class T>
BinaryTreeNode<T>::BinaryTreeNode(T& ele, BinaryTreeNode<T> * l, 
                                  BinaryTreeNode<T> * r){
    element = ele;
    leftChild = l;
    rightChild = r;
}

template<class T>
BinaryTreeNode<T> * BinaryTreeNode<T>::getLeftChild(){
    return leftChild;
}

template<class T>
BinaryTreeNode<T> * BinaryTreeNode<T>::getRightChild(){
    return rightChild;
}

template<class T>
T BinaryTreeNode<T>::getValue() const{
    return element;
}

template<class T>
bool BinaryTreeNode<T>::setLeftChild(BinaryTreeNode<T> * l){
    if(leftChild == nullptr){
        leftChild = l;
        return true;
    }
    else return false;
}

template<class T>
bool BinaryTreeNode<T>::setRightChild(BinaryTreeNode<T> * r){
    if(rightChild == nullptr){
        rightChild = r;
        return true;
    }
    else return false;
}

template<class T>
bool BinaryTreeNode<T>::isLeaf() const{
    if(leftChild == nullptr && rightChild == nullptr)
        return true;
    else return false;
}

template<class T>
BinaryTree<T>::BinaryTree(){
    root = nullptr;
}

template<class T>
BinaryTree<T>::BinaryTree(BinaryTreeNode<T> * r){
    root = r;
}

template<class T> 
BinaryTree<T>::~BinaryTree(){
    root = nullptr;
}

template<class T>
bool BinaryTree<T>::isEmpty() const{
    if (root == nullptr)    return true;
    else return false;
}

template<class T>
BinaryTreeNode<T> * BinaryTree<T>::getRoot() const{
    return root;
}

template<class T>
void BinaryTree<T>::visit(BinaryTreeNode<T> * pointer){
    std::cout<<pointer->element<<std::endl;
}

template<class T>
void BinaryTree<T>::preOrder(BinaryTreeNode<T> * root){
    using std::stack;
    stack<BinaryTreeNode<T> * > nodeStack;
    BinaryTreeNode<T> * pointer = root;
    while(!nodeStack.empty()||pointer != nullptr){
        if(pointer != nullptr){
            visit(pointer);
            if(pointer -> rightChild !=  nullptr)
                nodeStack.push(pointer->rightChild);
            pointer = pointer->leftChild;
        }
        else{
            pointer = nodeStack.top();
            nodeStack.pop();
        }
    }
}

template<class T>
void BinaryTree<T>::inOrder(BinaryTreeNode<T> * root){
    using std::stack;
    stack<BinaryTreeNode<T> * > nodeStack;
    BinaryTreeNode<T> * pointer = root;
    while(!nodeStack.empty()||pointer){
        if(pointer){
            nodeStack.push(pointer);
            pointer = pointer -> leftChild;
        }
        else{
            pointer = nodeStack.top();
            visit(pointer);
            pointer = pointer -> rightChild;
            nodeStack.pop();
        }
    }
}

template<class T>
void BinaryTree<T>::postOrder(BinaryTreeNode<T> * root){
    using std::stack;
    stack<BinaryTreeNode<T> * > nodeStack;
    BinaryTreeNode<T> * pointer = root;
    BinaryTreeNode<T> * pre = root;
    while(pointer != nullptr){
        while(pointer -> leftChild != nullptr){
            nodeStack.push(pointer);
            pointer = pointer -> leftChild;
        }
        while(pointer != nullptr && (pointer -> rightChild == nullptr ||
                                     pre == pointer->rightChild)){
            visit(pointer);
            pre = pointer;
            pointer = nodeStack.top();
            nodeStack.pop();
        }
        nodeStack.push(pointer);
        pointer = pointer -> rightChild;
    }
}

template<class T>
void BinaryTree<T>::levelOrder(BinaryTreeNode<T> * root){
    using std::queue;
    queue<BinaryTreeNode<T> *>nodeQueue;
    BinaryTreeNode<T> * pointer = root;
    if(pointer)
        nodeQueue.push(pointer);
    while(!nodeQueue.empty()){
        pointer = nodeQueue.front();
        visit(pointer);
        nodeQueue.pop();
        if(pointer->leftChild)  nodeQueue.push(pointer->leftChild);
        if(pointer->rightChild) nodeQueue.push(pointer->rightChild);
    }
}

main.cpp

#include"binarytree.h"
#include <iostream>

using namespace std;

int main(){
    int a1,a2,a3,a4,a5;
    cin>>a1>>a2>>a3>>a4>>a5;
    BinaryTreeNode<int> n1(a1),n2(a2),n3(a3),n4(a4),n5(a5);
    BinaryTree<int> t(&n1);
    n1.setLeftChild(&n2);
    n1.setRightChild(&n3);
    n2.setLeftChild(&n4);
    n2.setRightChild(&n5);          //真·随便接的
    cout<<"层次遍历:"<<endl;
    t.levelOrder(&n1);
    cout<<"前序遍历:"<<endl;
    t.preOrder(&n1);
    cout<<"中序遍历:"<<endl;
    t.inOrder(&n1);
    cout<<"后序遍历:"<<endl;
    t.postOrder(&n1);
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容