前序、中序、后序遍历的多种非递归实现
来源:互联网 发布:type c数据接口 编辑:程序博客网 时间:2024/05/21 06:53
其实过程很简单:一直往左走 root->left->left->left...->null,由于是前序遍历,因此一遇到节点,便需要立即访问;由于一直走到最左边后,需要逐步返回到父节点访问右节点,因此必须有一个措施能够对节点序列回溯。所以我们想到了用栈记忆的方法:在访问途中将依次遇到的节点保存下来。由于节点出现次序与恢复次序是反序的,因此是一个先进后出结构,需要用栈。使用栈记忆的实现有两个版本:第一个版本是跟踪指针移动用栈保存中间结果的实现方式,第二个版本是直接模拟递归。
一、跟踪指针移动用栈保存中间结果
前序遍历是在入栈前访问,中序遍历是在出栈时访问,后序遍历用这种方法不太好实现。
节点定义:
typedef struct BiNode{ int data; struct BiNode * lchild; struct BiNode * rchild;}BiNode,*BiTree;
前序遍历:
void preOrderBiTree(BiNode * root){if(root == NULL)return;BiNode * node = root;stack<BiNode*> nodes;while(node || !nodes.empty()){while(node != NULL){nodes.push(node);printf("%d",node->data);node = node -> lchild;}node = nodes.top();//回溯到父节点nodes.pop();node = node -> rchild;}}
每次都将遇到的节点压入栈,当左子树遍历完毕后才从栈中弹出最后一个访问的节点,访问其右子树。在同一层中,不可能同时有两个节点压入栈,因此栈的大小空间为O(h),h为二叉树高度。时间方面,每个节点都被压入栈一次,弹出栈一次,访问一次,复杂度为O(n)。
中序遍历:
void midOrderBinaryTree(BiNode * root){if(root == NULL)return;BiNode * node = root;stack<BiNode*> nodes;while(node || !nodes.empty()){while(node != NULL){nodes.push(node);node = node ->lchild;}node = nodes.top();printf("%d ",node ->data);nodes.pop();node = node ->rchild;}}
二、直接用栈来模拟递归,先序非常简单,而中序与后序难度一致,并且需要一个标记位来标记该节点是否被入栈过(其左右子树是否被访问过)。中序遍历和后序遍历的区别是当节点弹出后如果其isPushed为false,前者是右子树、该节点、左子树的次序入栈,后者是该节点、右子树、左子树的次序入栈。
前序遍历:
void preOrderBinaryTree(BiNode * pRoot){ if(pRoot == NULL) return;stack<BiNode *> sData; sData.push(pRoot); BiNode * pNode = NULL; while(!sData.empty()){ pNode = sData.top(); printf("%d ",pNode -> data); sData.pop(); if(pNode -> rchild != NULL){ sData.push(pNode -> rchild); } if(pNode -> lchild != NULL){ sData.push(pNode -> lchild); } }}
每次将节点压入栈,然后弹出,压右子树,再压入左子树,在遍历过程中,遍历序列的右节点依次被存入栈,左节点逐次被访问。同一时刻,栈中元素为m-1个右节点和1个最左节点,最高为h。所以空间也为O(h);每个节点同样被压栈一次,弹栈一次,访问一次,时间复杂度O(n)
typedef struct BiNodeWithTag{int data;struct BiNodeWithTag * lchild;struct BiNodeWithTag * rchild;bool isPushed;}BiNodeWithTag,*BiNodeWithTagPointer;
中序遍历:
void midOrderBinaryTree(BiNodeWithTag * root){if(root == NULL)return;stack<BiNodeWithTag *> nodes;BiNodeWithTag * node = root;nodes.push(node);while(!nodes.empty()){node = nodes.top();nodes.pop();if(node ->isPushed){printf("%d ",node ->data);continue;}if(node ->rchild != NULL)nodes.push(node ->rchild);nodes.push(node);node ->isPushed = true;if(node ->lchild != NULL)nodes.push(node ->lchild);}}
对比先序遍历,这个算法需要额外的增加O(n)的标志位空间。另外,栈空间也扩大,因为每次压栈的时候都压入根节点与左右节点,因此栈空间为O(n)。时间复杂度方面,每个节点压栈两次,作为子节点压栈一次,作为根节点压栈一次,弹栈也是两次。
后序遍历:
void postOrderBinaryTree(BiNodeWithTag * root){if(root == NULL)return;stack<BiNodeWithTag *> nodes;BiNodeWithTag * node = root;nodes.push(node);while(!nodes.empty()){node = nodes.top();nodes.pop();if(node ->isPushed){printf("%d ",node ->data);continue;}if(node ->rchild != NULL)nodes.push(node ->rchild);if(node ->lchild != NULL)nodes.push(node ->lchild);nodes.push(node);node ->isPushed = true;}}
参考:
http://blog.csdn.net/kofsky/article/details/2886453
- 前序、中序、后序遍历的多种非递归实现
- 非递归实现前序遍历+中序遍历得到后序遍历的结果
- 非递归实现二叉树的后序遍历、前序遍历、中序遍历
- 非递归实现前序、中序、后序遍历
- 二叉树非递归前、中、后序遍历实现
- java实现树的前序,中序,后序的递归和非递归遍历
- 树的前序,中序,后序遍历的递归以及非递归实现
- 二叉树 前序遍历的非递归实现 中序遍历的非递归实现 后序遍历的非递归实现 创建二叉树
- 二叉树的前序、中序、后序遍历 递归非递归实现
- 二叉树的前序、中序、后序(递归、非递归)遍历java实现
- 前序 中序 后序遍历的递归和非递归实现
- 二叉树的前序,中序,后序遍历(递归非递归实现)
- 实现二叉树的前序/中序/后序递归、非递归遍历
- 二叉树的前序,中序,后序遍历。用递归和非递归实现
- 【二叉树遍历算法】——前/中/后序递归与非递归的实现
- JAVA实现二叉树的前、中、后序遍历(递归与非递归)
- 前序,中序,后序遍历的非递归
- 二叉树的非递归【前/中/后 序遍历】
- linux 动态链接的使用
- Erlang多线程相关
- UFLDL 教程学习笔记(四)主成分分析
- 海量数据相似度计算之simhash短文本查找
- 模拟集成电路设计的九个层次
- 前序、中序、后序遍历的多种非递归实现
- JAVA中JButton常用设置
- 关于协方差矩阵的理解
- hdu2426 Interesting Housing Problem (KM邻接表)
- Linux 虚拟鼠标,键盘
- 28. 不要将你的程序钉成竖直
- linux环境下利用autotools工具自动生成make file
- hdu-1232-畅通工程//nyoj-608-畅通工程
- 设计模式之单例模式