树,是数据结构的重要组成部分。树分为前序、中序和后序遍历三种方式,下面以前序为例介绍遍历的实现方法。
一、递归法
void rPreprint(BinNode<Elem> r) {
if(r == null) return; //判断树节点是否为空
System.out.print(r.data + " "); //打印节点数据
rPreprint(r.left); //进入左子树
rPreprint(r.right); //进入右子树
}
优点:便于理解,实现方式简单;
缺点:当树深度较大时,递归需要占用大量栈空间,容易导致栈溢出。
二、循环遍历法(利用栈)
void iprepreint(BinNode<Elem> r) {
Stack<BinNode<Elem>> st; //创建栈
if(r == null) return; //树根为空则返回
while(r != null) {
System.out.println(r.data); //打印树节点数据
st.push(r); //节点压入堆栈
r = r.left; //进入左子树
while(r == null && !st.empty()){
//节点不存在并且堆栈不为空(为空则说明遍历完全部节点)
r = st.peek(); //取出栈顶节点(即进入左子树前的结点)
st.pop(); //弹出该节点(后面无需再遍历了)
r = r.right; //进入右子树(若右子树不为空,则结束小迭代)
}
}
}
1.实现思路
如下图:
①.
当遍历到节点“4”时,将节点“4”压入堆栈,进入左子树;
左子树为空,此时栈顶节点为“4”,则令r = 节点“4”,并弹出该节点(后续不再需要经过节点“4”了),然后进入右子树;
右子树仍然为空,此时栈顶节点为进入节点“4”之前的节点,即节点“2”,并弹出节点“2”;令r = 节点“2”,进入节点“2”的右子树;
②.
节点“2”的右子树为空,此时栈顶节点为进入节点“2”之前的节点,即节点“1”,令r = 节点“1”,并弹出节点“1”(此时栈空);
进入节点“1”的右子树,即节点“3”,打印节点“3”数据,并将节点“3”压入堆栈(此时栈里只有节点“3”);
进入节点“3”左子树,左子树为空,此时令r等于栈顶节点,即r = 节点“3”,并弹出栈顶(此时栈空);
进入节点“3”的右子树,即r = 节点“3”的right,此时r == null,并且栈为空,说明遍历全部完成,则退出两个循环。
2.优缺点
优点:只需占用很少的空间;
缺点:思路较难,实现起来较复杂。
以上为树的前序遍历,若想改成另外两种遍历方式,只需调节令r等于左右子树时的顺序就好,这里不再细讲。