非递归且不使用栈或者线索也可以遍历树
来源:互联网 发布:java 字符串格式化 编辑:程序博客网 时间:2024/06/05 06:48
以前总是不太喜欢把所学的知识记录下来,但是最近觉得,把装在脑袋里的一些东西释放出来,大脑能够更有效地去吸收新的营养。于是这次就决定试上一试,看看效果如何。
一般来说,我们对树的遍历要么是使用直观的递归遍历,要么是使用栈Stack,通过栈的操作实现对访问顺序的控制,前面这两种都是隐示或显示地使用栈来存储当前没有处理完的节点信息。在递归函数中,使用了运行时栈。在非递归的算法变体中,显式定义和使用了由用户维护的栈。程序要花费额外的时间来维护栈,还要为栈留出更多的空间。在最坏情况下,当树以不利于程序运行的方式“倾斜”时,栈将保存权中几乎所有节点的信息,这对于很大的树来说是一个严重的问题。
于是就想到,能不能既不使用栈或者线索也可以遍历树呢?事实上有许多这样的算法,它们都在遍历过程中对树进行了临时的修改,这些修改包括给某些指针重新赋新值,当然在完成遍历后,这些树结构需要恢复。
Joseph M.Morris 开发了一个精致的算法,它应用于中序遍历树:
template<class T>
void BST<T>::MorrisInorder(){ //中序遍历
BSTNode<T> *p = root, *tmp;
while (p != NULL){
if (p->left == NULL){
visit(p);
p = p->right;
}
else {
tmp = p->left;
while (tmp->right != NULL && tmp->right != p){
//go to the rightmost nodeof the left subtree
//or to the temporary parent of p;
tmp = tmp->right;
}
if (tmp->right == NULL){
tmp->right = p;//if 'true' rightmost node was reached,
p = p->left; //make it a temporary parent of the current root
}
else {//else a temporary parent hasbeen found;
//visit node p and then cut the rigth pointer of the current parent,
//whereby it ceases to be a parent;
visit(p);
tmp->right = NULL;
p = p->right;
}
}
}
}
很容易从中序遍历算法中得到前序遍历算法,只需要将 visit() 从内层的 else 子句移到内层的的 if 子句就可以了。这样,节点就在树转换之前访问:
template<class T>
void BST<T>::MorrisPreorder(){ //前序遍历
BSTNode<T> *p = root, *tmp;
while (p != NULL){
if (p->left == NULL){
visit(p);
p = p->right;
}
else {
tmp = p->left;
while (tmp->right != NULL && tmp->right != p){
tmp = tmp->right;
}
if (tmp->right == NULL){
visit(p);
tmp->right = p;
p = p->left;
}
else {
tmp->right = NULL;
p = p->right;
}
}
}
}
后序遍历也可以从中序遍历算法中得到:首先创建一个哑节点,它的左子树是正在处理的树,它的右子树是空。接着,这棵临时扩展的树就成为遍历的主体,与中序遍历的树类似,但在内层的 else 子句中,在找到临时的父节点后,p->left(已包含)和 p已排除)之间、在修改的树中扩展到右侧的节点是以相反的顺序处理的。而这种逆序处理依赖于在向下扫描节点时,顺便翻转节点链的右指针,以指向节点的的父节点。然后,在找到临时的父节点 p 时便向上扫描节点链,访问每个节点,并将右指针恢复为原来的值: template<class T> void BST<T>::MorrisPostorder(){ //后序遍历 BSTNode<T> Root, *p = &Root, *tmp, *p1, *p2; Root->left = root; //哑节点的左子树是正在处理的树 while (p != NULL){ if (p->left == NULL){ p = p->right; } else { tmp = p->left; while (tmp->right != NULL && tmp->right != p){ tmp = tmp->right; } if (tmp->right == NULL){ tmp->right = p; p = p->left; } else { tmp->right = NULL; tmp = p->left; p1 = tmp->right; while (p1 != NULL){ p2 = p1->right; p1->right = tmp; tmp = p1; p1 = p2; } while (tmp != p->left){ visit(tmp); p1 = tmp->right; tmp->right = p2; p2 = tmp; tmp = p1; } visit(tmp); p = p->right; } } } }
- 非递归且不使用栈或者线索也可以遍历树
- 前,中,后序遍历二叉树 (递归 && 非递归的栈 && 非递归非栈的线索二叉树)
- 二叉树遍历--递归--非递归--线索化
- 二叉树遍历--递归--非递归--线索化
- 二叉树线索化后 非递归遍历
- 无栈非递归中序遍历非线索化二叉树
- 不使用存储结构(非栈、非递归)遍历二叉树
- 二叉树非递归遍历,不使用栈(前序,中序,后续)
- c++模板实现二叉树,线索化,线索化遍历,非递归遍历及一些基本操作
- 递归 栈 线索 中序遍历二叉树
- 树(2)--二叉树的遍历(非递归)+线索二叉树
- 二叉树的非递归中序遍历(二叉线索存储结构)
- 二叉树的非递归遍历(使用栈)
- 算法基础 - 非递归使用栈遍历树
- 使用栈,非递归先序遍历二叉树T
- 使用栈,非递归中序遍历二叉树T
- 使用栈,非递归后序遍历二叉树PT
- 二叉树递归遍历与非递归遍历的栈空间使用
- 在ASP.NET中,字符串的分割简单示例
- HBase的领导人探讨Hadoop、BigTable和分布式数据库
- oracle中的savepoints是什么
- ASP.NET MVC小论
- 今天复习的stl
- 非递归且不使用栈或者线索也可以遍历树
- 为TextField设置光标
- QTP的学习方法及总结
- Dreamweaver- jquery提示
- 两个效果蛮好的javascript幻灯片(Jquery slider)
- 数据库设计准则(第一、第二、第三范式说明)
- 回溯算法
- 一个经常被忽略的关于更新异常的问题
- 十种最神奇的快速减肥偏方