body, table{font-family: 微软雅黑; font-size: 13.5pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}

二叉树遍历图解示意图可以参考《大话数据结构》P175,看了这个过程能更好的理解算法,作者博客地址:http://cj723.cnblogs.com/

图一:
前序遍历:abc
中序遍历:bac
后序遍历:bca
图二:
前序遍历:ABCDEF
中序遍历:CBAEDF
后序遍历:CBEFDA
#include<iostream>
#include<stack>
using namespace std;
typedef struct BinaryTree
{
        char data;
        struct BinaryTree* lchild;
        struct BinaryTree* rchild;
}binaryTreeNode,*pBinaryTree;
int createBinaryTree(pBinaryTree& root);
//非递归实现前序遍历,利用栈来模拟递归过程
void preorderTraversalNonRecursion(pBinaryTree root); 
//非递归实现中序遍历,利用栈来模拟递归过程
void inorderTraversalNonRecursion(pBinaryTree root);
//非递归实现后序遍历,利用栈来模拟递归过程
void postorderTraversalNonRecursion(pBinaryTree root);
int createBinaryTree(pBinaryTree& root)
{
        char data;
        if(cin>>data)
        {
                if('#'==data)  //输入#表示该结点为空
                {
                        root = NULL; 
                        return -1;  //只要当输入是#才会返回-1,表示空树
                }               
                //建立根结点
                binaryTreeNode* node = new binaryTreeNode();
                node->data = data;
                root = node;
                //递归去建立左子树
                createBinaryTree(root->lchild);
                //递归去建立右子树
                createBinaryTree(root->rchild);
        }
        return 0;   //最终递归返回的是0;
}
void preorderTraversalNonRecursion(pBinaryTree root)
{//访问节点顺序是:根结点,左子树,右子树;针对左右子树,又是按照根左右的顺序访问,所有这个过程中要记录根结点
        if(nullptr==root)
                return;
        stack<binaryTreeNode*> rootNode;  //遍历过程中记录根结点
        while(!rootNode.empty()||
                nullptr!=root)
        {
                while(nullptr!=root)
                {
                        cout<<root->data<<" ";  //输出根结点
                        //遍历左子树
                        rootNode.push(root);  //记录左子树的根结点,前序遍历回溯访问右子树的时候要用到
                        root = root->lchild;
                }//一直遍历到最左边的最后一个结点,肯定左子树为空了,出while循环,这时候就要回溯访问右子树了
                if(!rootNode.empty())
                {
                        root = rootNode.top();  //栈中取出最近入栈的根结点
                        root = root->rchild;  //根结点指向右子树
                        rootNode.pop();  //最近压栈的根结点弹栈
                        //右子树也是一棵二叉树,又回到第二个while循环,前序遍历,根左右的方法访问右子树
                }
                else
                        root = NULL;
        }
}
void inorderTraversalNonRecursion(pBinaryTree root)
{//左子树,根结点,右子树
        if(nullptr==root)
                return ;
        stack<binaryTreeNode*> rootNode;
        while(nullptr!=root||
                !rootNode.empty())
        {
                while(nullptr!=root)
                {
                        rootNode.push(root);  //栈中保存根结点,先去访问左子树
                        root = root->lchild;
                }//左子树遍历完毕
                cout<<rootNode.top()->data<<" ";  //访问根结点
                root = rootNode.top()->rchild;  //访问右子树
                rootNode.pop();  //出栈最近保存的结点
        }
}
typedef struct Traversal
{
        binaryTreeNode* rootAddr;  //二叉树结点地址
        bool accessToken;  //访问标记
}traversalInfo,*pTraversal;
void postorderTraversalNonRecursion(pBinaryTree root)
{//后序遍历,左子树,右子树,根结点
        //遍历完左子树后要回溯到根结点去遍历右子树,所以需要一个标记来记录根结点,如果是第二次遍历到就直接输出值
        if(nullptr==root)
                return ;
        stack<traversalInfo> rootNodeIndo;
        while(nullptr!=root)  //二叉树根结点最后才会访问
        {
                //遍历左子树
                traversalInfo tmp;
                tmp.rootAddr = root;
                tmp.accessToken = false;  //第一次访问,第二次访问修改为true,输出信息
                rootNodeIndo.push(tmp);  //遍历右子树沿途的根结点入栈
                root = root->lchild;
        }//开始回溯遍历右子树
        while(!rootNodeIndo.empty())
        {
                root = rootNodeIndo.top().rootAddr;  //取出最近访问的根结点
                //遍历右子树
                while(nullptr!=root->rchild&&
                        !rootNodeIndo.top().accessToken)  //右子树不空,并且根结点只存在第一次访问
                {
                        rootNodeIndo.top().accessToken = true;  //根结点第二次访问,修改为true,下次回溯访问到就要输出
                        //右子树根结点进栈
                        root = root->rchild;
                        traversalInfo tmp;
                        tmp.rootAddr = root;
                        tmp.accessToken = false;
                        rootNodeIndo.push(tmp);
                        //右子树的左子树不空,接着遍历左子树
                        while(nullptr!=root->lchild)
                        {
                                root = root->lchild;
                                traversalInfo tmp;
                                tmp.rootAddr = root;
                                tmp.accessToken = false;
                                rootNodeIndo.push(tmp);
                        }//右子树的左子树遍历完毕,回溯遍历右子树的右子树。
                }
                //输出结点信息
                //执行下面语句只有两种情况,1、对应二叉树最左边结点没有右子树,包括右子树的最左边结点
                //2、回溯再次访问到根结点,即第3个while循环的第二个条件!rootNodeIndo.top().accessToken不满足
                cout<<rootNodeIndo.top().rootAddr->data<<" ";
                rootNodeIndo.pop();  //出栈
        }
}

int main()
{
        pBinaryTree root = nullptr;
        int ret = createBinaryTree(root);
        if(0==ret)
        {
                cout<<"preorder traversal non-recursion:"<<endl;
                preorderTraversalNonRecursion(root);
                cout<<endl<<endl;;
                cout<<"inorder traversal non-recursion:"<<endl;
                inorderTraversalNonRecursion(root);
                cout<<endl<<endl;;
                cout<<"postorder traversal non-recursion:"<<endl;
                postorderTraversalNonRecursion(root);
                cout<<endl;
        }
        cout<<endl;
        system("pause");
}

//后序遍历算法优化
typedef struct Traversal
{
        binaryTreeNode* rootAddr;  
        bool accessToken; 
}traversalInfo,*pTraversal;
void stackPush(stack<traversalInfo>& rootNodeInfo,binaryTreeNode* &rootAddr,bool&& flag)
{
        traversalInfo tmp;
        tmp.rootAddr = rootAddr;
        tmp.accessToken = flag; 
        rootNodeInfo.push(tmp);
}
void postorderTraversalNonRecursion(pBinaryTree root)
{
        if(nullptr==root)
                return ;
        stack<traversalInfo> rootNodeInfo;
        while(nullptr!=root) 
        {
                stackPush(rootNodeInfo,root,false);
                root = root->lchild;
        }
        while(!rootNodeInfo.empty())
        {
                root = rootNodeInfo.top().rootAddr; 
                while(nullptr!=root->rchild&&
                        !rootNodeInfo.top().accessToken) 
                {
                        rootNodeInfo.top().accessToken = true; 
                        root = root->rchild;
                        stackPush(rootNodeInfo,root,false);
                  
                        while(nullptr!=root->lchild)
                        {
                                root = root->lchild;
                                stackPush(rootNodeInfo,root,false);
                        }
                }
                cout<<rootNodeInfo.top().rootAddr->data<<" ";
                rootNodeInfo.pop();  
        }
}

非递归实现二叉树的三种遍历操作,C++描述的更多相关文章

  1. PTA 二叉树的三种遍历(先序、中序和后序)

    6-5 二叉树的三种遍历(先序.中序和后序) (6 分)   本题要求实现给定的二叉树的三种遍历. 函数接口定义: void Preorder(BiTree T); void Inorder(BiTr ...

  2. 基于Java的二叉树的三种遍历方式的递归与非递归实现

    二叉树的遍历方式包括前序遍历.中序遍历和后序遍历,其实现方式包括递归实现和非递归实现. 前序遍历:根节点 | 左子树 | 右子树 中序遍历:左子树 | 根节点 | 右子树 后序遍历:左子树 | 右子树 ...

  3. C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)

    树 利用顺序存储和链式存储的特点,可以实现树的存储结构的表示,具体表示法有很多种. 1)双亲表示法:在每个结点中,附设一个指示器指示其双亲结点在数组中的位置. 2)孩子表示法:把每个结点的孩子排列起来 ...

  4. 大数据学习day13------第三阶段----scala01-----函数式编程。scala以及IDEA的安装,变量的定义,条件表达式,for循环(守卫模式,推导式,可变参数以及三种遍历方式),方法定义,数组以及集合(可变和非可变),数组中常用的方法

    具体见第三阶段scala-day01中的文档(scala编程基础---基础语法)  1. 函数式编程(https://www.cnblogs.com/wchukai/p/5651185.html): ...

  5. java:数据结构(四)二叉查找树以及树的三种遍历

    @TOC 二叉树模型 二叉树是树的一种应用,一个节点可以有两个孩子:左孩子,右孩子,并且除了根节点以外每个节点都有一个父节点.当然这种简单的二叉树不能解决让树保持平衡状态,例如你一直往树的左边添加元素 ...

  6. map的三种遍历方法!

    map的三种遍历方法!   集合的一个很重要的操作---遍历,学习了三种遍历方法,三种方法各有优缺点~~ /* * To change this template, choose Tools | Te ...

  7. 二叉树及其三种遍历方式的实现(基于Java)

    二叉树概念: 二叉树是每个节点的度均不超过2的有序树,因此二叉树中每个节点的孩子只能是0,1或者2个,并且每个孩子都有左右之分. 位于左边的孩子称为左孩子,位于右边的孩子成为右孩子:以左孩子为根节点的 ...

  8. javase-常用三种遍历方法

    javase-常用三种遍历方法 import java.util.ArrayList; import java.util.Iterator; import java.util.List; public ...

  9. Java中Map的三种遍历方法

    Map的三种遍历方法: 1. 使用keySet遍历,while循环: 2. 使用entrySet遍历,while循环: 3. 使用for循环遍历.   告诉您们一个小秘密: (下↓面是测试代码,最爱看 ...

随机推荐

  1. Unity --- 纹理压缩基本知识点

    1.Unity支持的压缩格式的分类,这里主要指Android平台和IOS平台: DXT格式 --- Nvidia Tegra(图睿)提供ETC  --- 安卓原生支持的,OPNEGL2.0都支持,ET ...

  2. HeadFirst Ruby 第十五章总结 Saving and loading data

    前言 在上一章讲述了如何进行基础的操作,比如 处理 GET 请求的 get route, 再比如下载 gem 等等方面的知识.在这一章节,作者告诉我们如何储存.处理数据.整个过程分三步走: 首先,当 ...

  3. Ruby 基础教程 第一部分总结

    第一部分:Ruby 初体验 第一章: Ruby 初探 前言 开头的这一章节讲了一些十分基础的内容,重要的几个话题有: ruby 命令的执行方法 对象.方法的概念 常见的打印方法 ruby 命令的执行方 ...

  4. C#使用 System.Net.Mail发送邮件功能

    .NET 里包含了很多很丰富的邮件发送与接受的API在 System.Net.Mail命名空间里,使得我们开发发送和接受邮件相关功能变得简单,下面是一个简单发送邮件的功能: private void ...

  5. 10 Node Frameworks to Use in 2019

    原文 https://scotch.io/bar-talk/10-node-frameworks-to-use-in-2019 node Framworks列表: http://nodeframewo ...

  6. 【转】预装Win8/8.1 中文版系统升级为专业版或专业版含媒体中心版的简单方法

    [转]预装Win8/8.1 中文版系统升级为专业版或专业版含媒体中心版的简单方法 原文地址:http://www.iruanmi.com/upgrade-win8-china-to-a-higher- ...

  7. php获得时间段的月

    1.时间:$start_time = $_GET['start_time']; //2015-01$end_time = $_GET['end_time']; //2015-052.对时间进行拆分:$ ...

  8. js 处理 cookie的存储与删除

    <script> //JS操作cookies方法! //写cookies function setCookie(c_name, value, expiredays){ var exdate ...

  9. MySql习题和答案

    MySQL测试题 一.表关系请创建如下表,并创建相关约束 二.操作表 1.自行创建测试数据 2.查询“生物”课程比“物理”课程成绩高的所有学生的学号.ps:针对的是自己的生物成绩比物理成绩高,再把符合 ...

  10. 一、持久层框架(Hibernate)

    一.Hibernate 使用JDBC做数据库相关功能开发会做很多重复性的工作,创建连接,关闭连接,把字段逐一映射到属性中等.Hibernate把这些进行封装起来,使得数据库访问变得轻松简单. 1.创建 ...