无空间复杂度(无栈)的非递归二叉树中序遍历
来源:互联网 发布:c语言中的函数调用 编辑:程序博客网 时间:2024/04/29 23:32
常见的二叉树非递归算法都是用栈保存访问路径上的结点,这样使空间复杂为o(n),其中n为树最大深度。空间复杂度为o(1)的算法并没有以牺牲时间复杂度为代价,它只是巧妙的运用叶子结点左右孩子指针为空这一事实,将所有的叶子组成一链栈用于保存回退信息,其中叶子结点的lchild域相当于链表的data域,rchild相当于链表的next域,是一种“废物利用”的思想,本质上还是用了栈,只是没用分配栈空间而已。
事实上,像二叉树这种递归定义的非线性结构,在设计相应的非递归程序时最难考虑的是从当前结点向上回退的情况,向下走的情况很简单:先向左走,左面走不下去了就向右。回退的时候有两个要点:
1,找到其父结点的指针以便回退。
2,判断出它是父结点的左孩子还是右孩子。常见的用栈保存信息的算法,栈中保存了从根结点到当前结点的路径信息,当然可以正确的回退。
该算法的大概思想是:p作为当前结点,q作为它的父结点(满足要点1),如此深入下去,如果p是q的左孩子,就把q的左指针指向q的父亲,这样q作指针所指向的结点就不在是p了,而是p的爷爷结点了,这样的做法是为了在回退时找到父结点。为了满足要点2:判断回退时它是父结点的左孩子还是右孩子,有三种情况要考虑:1,回退时如果q的lchild为空,表示q只有右子树p,这样就判断出来了p只可能是q的右孩子,剩下的问题就是回退和恢复q的rchild了。2,如果q的rchild为空,这个情况和1相似......3,如果q的lchild和rchild都不为空,这样回退时候就比较难判断p到底是q的左还是右儿子了?该算法的解决方法为:用av保存当前叶子结点以作为为栈分配的元素,这个栈用于记录遇到的双子树结点。 具体操作如下:
av->rchild=top;
top=av; lr=q;
lr=r->lchild; /**//*lchild相当于链表的data域,rchild相当next域*/
top=r->rchild;
r->lchild=r->rchild=NULL;/**//*退栈结束*/
用lr表示当前遇到的双子树结点,也就是p从q的lchild域回退时才判断出来q有两个子树(怎知道是lchild回退?这是程序技巧问题,看程序!),这时就把q记录在lr内,这时lr并不急于进av栈,只有当lr的右子树中还有双子树结点时,lr才进栈!如果lr的右子树中没有双子树结点,那么当p回退的时候如果碰到了lr就表示p为q的右儿子,具体算法还要看程序说明。 至于作为栈的叶子结点是完全够用的,这是由中序遍历的性质决定的,因为只有访问了一个叶子结点才有可能访问一个双子树结点。
void InOrder2(BiTree T) ...{
BiTree top=NULL,lr=NULL,r,av,
p=T,q=T;
/**//*top为栈顶指针,lr记录当前2子树结点,r为临时变量,
av为当前可用叶子结点,p为当前访问结点,q为p的父亲结点*/
if(T==NULL) return ;
while(1) ...{ /**//*向下访问搜索*/
while(1) ...{
if(p->lchild==NULL&&p->rchild==NULL) ...{/**//*如果访问到底,就输出该结点*/
printf("%c ",p->data);
break;
}
else if(p->lchild==NULL) ...{/**//*沿左子树访问到底,转向访问右子树*/
printf("%c ",p->data);
r=p->rchild;
p->rchild=q;
q=p; p=r;
}
else ...{/**//*一直沿左子树访问下去*/
r=p->lchild;
p->lchild=q;
q=p; p=r;
}
}
av=p;/**//*p为叶子结点,av记录当前叶子结点*/
while(1) ...{
if(p==T) return;/**//*如果回退到根,返回*/
else if(q->lchild==NULL) ...{/**//*如果父结点q的lchild为空,
表示p为q的右儿子*/
r=q->rchild; /**//*向父结点的右儿子方向回退*/
q->rchild=p; /**//*重新连接父指针*/
p=q; q=r;
}
else if(q->rchild==NULL) ...{/**//*类似上面*/
r=q->lchild;
q->lchild=p;
p=q; q=r;
printf("%c ",p->data);
}
else ...{/**//*如果p的父亲q有两个子树,用以下方法判断p是q的左儿子还是右儿子*/
if(q==lr) ...{/**//*p是q的右儿子*/
r=top; /**//*退栈*/
lr=r->lchild; /**//*lchild相当于链表的data域,rchild相当next域*/
top=r->rchild;
r->lchild=r->rchild=NULL;/**//*退栈结束*/
r=q->rchild;
q->rchild=p;
p=q; q=r;
}
else ...{ /**//*p是q的左儿子*/
printf("%c ",q->data);
av->lchild=lr;/**//*入栈加回退操作*/
av->rchild=top;
top=av; lr=q;
r=q->lchild;
q->lchild=p;
p=q->rchild;
q->rchild=r;
break;
}
}
}
}
}
- 无空间复杂度(无栈)的非递归二叉树中序遍历
- 二叉树中序遍历(无递归无栈,常数空间复杂度)
- 【算法】二叉树的非递归遍历的简洁写法/迭代器实现/O(1)空间复杂度的Morris遍历
- 二叉树递归遍历与非递归遍历的栈空间使用
- 二叉树的非递归遍历(不用栈、O(1)空间)
- 二叉树中序遍历(递归+非递归)
- 二叉树中序遍历的非递归算法
- 二叉树中序遍历的非递归算法
- 二叉树中序遍历的非递归方法
- 二叉树中序遍历的非递归实现
- 二叉树中序遍历的非递归算法
- 二叉树的遍历(递归+非递归+层次遍历)
- 二叉树的遍历(非递归)
- 二叉树的遍历(非递归)
- 二叉树的遍历(非递归)
- 二叉树 后序遍历 无tag域非递归实现
- 二叉树中序遍历(递归、栈实现非递归、不用栈实现非递归)
- 二叉树的非递归遍历(使用栈)
- 四川地震
- WinAPI: ShellExecute - 打开外部程序或文件
- 关于microwindows中多线程的问题
- 总结的一些计算机专有名词解释
- WinExec(打开外部文件)
- 无空间复杂度(无栈)的非递归二叉树中序遍历
- Enumeration 在获取页面的信息应用
- ORACLE RAC安装问题解决记录(3)- SYS用户不支持TAF故障切换
- 看看你的C语言到底什么水平吧
- 部分C++面试题答案
- JavaScript经典效果集锦(转)
- C语言面试题大汇总之华为面试题
- 存储图片到数据库中的一个异常信息
- ATL接口映射宏详解[1]