前中后序
.和层序遍历梳理一遍。队列,递归,和栈
。这里笔者都有进行过详细介绍,能够关注笔者数据结构与算法专栏。持续分享,共同窗习。有左右节点
。而每一层一层的遍历都和左右节点有着很大的关系。也就是咱们选用的数据结构不能一股脑的往一个方向钻,而
左右应该均衡考虑
。这样咱们就选用
队列来实现。
第二层
每一个执行的时候添加到队列
,那么添加的全部节点都在第二层后面
。pop遍历第n层
的节点,每一个节点会push左右两个节点进去
。可是队列先进先出。它会放到队尾(下一层
)。直到第n层的最后一个pop出来
,第n+1层的还在队列中整齐排着。这就达到一个层序
的效果。实现的代码也很容易理解:java
public void cengxu(node t) {//层序遍历
Queue<node> q1 = new ArrayDeque<node>();
if (t == null)
return;
if (t != null) {
q1.add(t);
}
while (!q1.isEmpty()) {
node t1 = q1.poll();
if (t1.left != null)
q1.add(t1.left);
if (t1.right != null)
q1.add(t1.right);
System.out.print(t1.value + " ");
}
System.out.println();
}
复制代码
其实这种就是一个相似dfs的思想。用递归实现。前面有很详细的介绍递归算法。咱们采用的三序遍历是采用同一个递归。而且你们也都直到递归是一个有来有回的过程。三序遍历只是利用了递归中的来回过程当中不一样片断截取输出,而达到前(中、后序遍历的结果)。node
前序的规则就是根结点 ---> 左子树 ---> 右子树
.咱们在调用递归前进行节点操做。对于前序,就是先访问(输出)该节点。而递归左,递归右侧,会优先递归左侧。直到没有左节点
。才会中止。访问次序大体为: 算法
public void qianxu(node t)// 前序递归 前序遍历:根结点 ---> 左子树 ---> 右子树 {
if (t != null) {
System.out.print(t.value + " ");// 当前节点
qianxu(t.left);
qianxu(t.right);
}
}
复制代码
有了前序的经验,咱们就很好利用递归实现中序遍历。中序遍历的规则是:左子树---> 根结点 ---> 右子树
。因此咱们访问节点的顺序须要变。数据结构
来回
的过程,对于刚好有两个子节点(子节点无节点)的节点来讲。只须要访问一次左节点,访问根,访问右节点
。便可。一颗子树
,也要知足中序遍历要求
。因此就要先访问左节点的左节点(若是存在)。那么若是你这样想,规则虽然懂了。可是也太复杂了。那么咱们借助递归。由于它的子问题和根节点的问题一致,只是范围减少
了。因此咱们使用递归思想来解决。代码为:函数
public void zhongxu(node t)// 中序遍历 中序遍历:左子树---> 根结点 ---> 右子树 {
if (t != null) {
zhongxu(t.left);
System.out.print(t.value + " ");// 访问完左节点访问当前节点
zhongxu(t.right);
}
}
复制代码
同理,有了前面的分析,后续就是左子树 ---> 右子树 ---> 根结点
学习
public void houxu(node t)// 后序遍历 后序遍历:左子树 ---> 右子树 ---> 根结点 {
if (t != null) {
houxu(t.left);
houxu(t.right);
System.out.print(t.value + " "); // 访问玩左右访问当前节点
}
}
复制代码
递归有时候在效率
方面不是使人满意的。 利用栈,咱们直到栈的顺序为现金先出。那么顺序如何添加?递归是左递归,右递归。可是利用栈要相反,由于若是左进栈、右进栈
会出现如下后果:
再右节点进栈,左节点进栈
。而后循环一直到最后会一直优先取到左节点。达到和递归顺序相仿效果。
public void qianxu3(node t)// 非递归前序 栈 先左后右 t通常为root {
Stack<node> q1 = new Stack<node>();
if (t == null)
return;
if (t != null) {
q1.push(t);
}
while (!q1.empty()) {
node t1 = q1.pop();
if (t1.right != null) {
q1.push(t1.right);
}
if (t1.left != null) {
q1.push(t1.left);
}
System.out.print(t1.value + " ");
}
}
复制代码
方法二和非递归中序遍历的方法相似,只不过须要修改输出时间,在进栈时候输入访问节点便可。具体参考中序遍历分析。测试
public void qianxu2(node t) {
Stack<node> q1 = new Stack();
while(!q1.isEmpty()||t!=null)
{
if (t!=null) {
System.out.print(t.value+" ");
q1.push(t);
t=t.left;
}
else {
t=q1.pop();
t=t.right;
}
}
}
复制代码
非递归中序和前序有所区别。 咱们直到中序排列的顺序是:左节点,根节点,右节点
。那么咱们在通过根节点的前面节点 不能释放, 由于后面还须要用到它。因此要用栈先储存
。 它的规则大体为:spa
依次存入左节点全部点
,直到最左侧在栈顶。抛出栈顶并访问
。(例如第一个抛出2)。若是有右节点。那么将右节点加入栈中
,而后右节点一致左下遍历直到尾部。(这里5和7没有左节点,因此不加)可是若是抛出15
。右节点加入23
.再找23的左侧节点加入栈顶。就这样循环下去直到栈为空
。可行性分析:中序是左—中—右
的顺序。访问完左侧。当抛出当前点的时候说明左侧已经访问完(或者本身就是左侧),那么须要首先访问当前点的右侧。那么这个右节点把它当成根节点重复相同操做
(由于右节点要知足先左再右的顺序)。这样其实就是模拟了一个递归的过程,须要本身思考。 .net
public void zhongxu2(node t) {
Stack<node> q1 = new Stack();
while(!q1.isEmpty()||t!=null)
{
if (t!=null) {
q1.push(t);
t=t.left;
}
else {
t=q1.pop();
System.out.print(t.value+" ");
t=t.right;
}
}
}
复制代码
实现代码2:(我的首次写的)3d
public void zhongxu3(node t)// 先储藏全部左侧点,抛出一个点,访问该点右节点,对右节点在储存全部子左节点 {
Stack<node> q1 = new Stack();
if (t == null)
return;
if (t != null) {
q1.push(t);
}
node t1 = q1.peek();// 不能抛出,要先存最左侧
while (t1.left != null) {
t1 = t1.left;
q1.push(t1);
}
while (!q1.isEmpty()) {
node t2 = q1.pop();
System.out.print(t2.value + " ");
if (t2.right != null) {
t2 = t2.right;
q1.push(t2);
while (t2.left != null) {
t2 = t2.left;
q1.push(t2);
}
}
}
}
复制代码
非递归后序遍历有两种方法 一种方法是利用和前面中序、前序第二种方法相似的方法进入压栈出栈,可是要借助额外的标记次数
,一个节点访问第二次才能输出。(这个访问第一次是入栈
,第二次是子树解决完毕本身即将出栈
(先不出栈))。
在前面的前序和中序先到最左侧压入栈的时候,两种顺序依次是
中入栈
——>左入栈
——>左出栈——>中出栈——>右入栈
——>右孩子入出——>右出栈 在入栈时候操做便可前序左出栈
——>中出栈
——>右入栈 ——>右孩子入出——>右出栈
按照出栈顺序便可完成中序而在后序遍历中:它有这样的规则:
即将出栈
。第二次访问,public void houxu2(node t) {
Stack<node> q1 = new Stack();
Map<Integer,Integer >map=new HashMap<>();
while(!q1.isEmpty()||t!=null)
{
if (t!=null) {
q1.push(t);
map.put(t.value, 1); //t.value标记这个值节点出现的次数
t=t.left;
}
else {
t=q1.peek();
if(map.get(t.value)==2) {//第二次访问,抛出
q1.pop();
System.out.print(t.value+" ");
t=null;//须要往上走
}
else {
map.put(t.value, 2);
t=t.right;
}
}
}
}
复制代码
另外一种方法是借助双栈进行处理。咱们曾在前序方法一
借助一个栈右压,左压。持续让达到一个前序遍历的效果。可是这个方法很难实现后续。
先压左,再压右
,那么咱们得到的顺序将是和前序彻底相反的顺序(顺序为:中间,右侧,左侧
。倒过来恰好是左侧、右侧、中间的后续)对称看起来的前序。即用另外一个栈将序列进行反转顺序
!
public void houxu3(node t)// q1和q2 q1要先右后左,先遍历右侧,q1先装右侧就把右侧放到前面,左侧放在上面(栈顶) {
Stack<node> q1 = new Stack();
Stack<node> q2 = new Stack();
if (t == null)
return;
if (t != null) {
q1.push(t);
}
while (!q1.isEmpty()) {
node t1 = q1.pop();
q2.push(t1);
if (t1.left != null) {
q1.push(t1.left);
}
if (t1.right != null) {
q1.push(t1.right);
}
}
while (!q2.isEmpty()) {
node t1 = q2.pop();
System.out.print(t1.value + " ");
}
}
复制代码
测试结果:
bigsai
)。笔者认真更新数据结构与算法
。有兴趣能够关注一波学一块儿学习。回复数据结构或者爬虫有精心准备学习资料赠送。