最近在学习二叉树,第一次写博客,总结一下,方便以后复习。
先序遍历(根-左-右)
递归算法
public void preorder(BinaryNode<T> node){ //先根次序遍历二叉树
if (node!=null){
System.out.print(node.data.toString()+" ");
preorder(node.left);
preorder(node.right);
}
}
非递归算法
借助一个栈实现
public void preorderTraverse(BinaryNode node){//非递归中根次序遍历二叉树,借助栈
if (node==null)
System.out.println("该树为空树");
Stack stack=new Stack();
while (!stack.isEmpty()||node!=null){ //栈非空或者该结点非空
if (node!=null){ //若该结点非空,则访问并压栈
System.out.print(node.data.toString()+" ");
stack.push(node);
node=node.left;
}
else { //当左边的孩子访问完
node=(BinaryNode) stack.pop();//把左孩子结点弹出
node=node.right;//访问右边的
}
}
}
中序遍历(左-根-右)
递归算法
public void inorder(BinaryNode<T> node){ //中根次序遍历二叉树.递归法
if (node!=null){
inorder(node.left);
System.out.print(node.data.toString()+" ");
inorder(node.right);
}
}
非递归算法
public void inorderTraverse(BinaryNode node){//非递归中根次序遍历二叉树,借助栈
if (node==null)
System.out.println("该树为空树");
Stack stack=new Stack();
while (!stack.isEmpty()||node!=null){
if (node!=null){ //把左边的结点都压栈,根结点最后放在栈底
stack.push(node);
node=node.left;
}
else {
node=(BinaryNode) stack.pop(); //接着弹栈并打印该结点
System.out.print(node.data.toString()+" ");
node=node.right; //访问右孩子
}
}
}
后序遍历(左-右-根)
递归算法
public void postOrder(BinaryNode<T> p) //后根次序遍历以p结点为根的子二叉树,递归方法
{
if (p!=null)
{
postOrder(p.left);
postOrder(p.right);
System.out.print(p.data.toString()+" ");
}
}
非递归算法
1、这里和先序以及中序的不太一样,不能简单的换一下顺序,后序遍历先访问左孩子然后是右孩子,两者是兄弟结点,没有必然的联系,所以我第一个想到的是借助两个栈,每次把根结点压入原栈中,然后再弹出放到辅助栈中,接着把左右孩子压入原栈中,再弹出,直到原栈空为止,再打印出辅助栈的元素,就是后序序列。
public void postorderTraverse(){//实现二叉树后根次序遍历的非递归算法,借助两个栈实现
Stack stack=new Stack();
Stack stackHelp=new Stack();//辅助栈
if (this.root==null)
return;
BinaryNode node=this.root;
stack.push(node);//把根结点压入栈中
while (!stack.isEmpty()){ //栈非空时
node=(BinaryNode)stack.pop();//弹出根结点,并把根节点弹入辅助栈
stackHelp.push(node);
if (node.left!=null)//把左右孩子结点压入栈中
stack.push(node.left);
if (node.right!=null)
stack.push(node.right);
}
while (!stackHelp.isEmpty()){//最后把辅助栈的元素全部弹出
System.out.print(((BinaryNode) stackHelp.pop()).data.toString()+" ");
}
}
2、两个栈进行遍历,如果数据量大,会造成存储浪费,时间效率也会降低,下面的代码借助一个栈实现,用front标记其在后根次序的前驱结点。(这里Stack封装类没有get()方法,要创建一个LinkedStack类来获取栈顶元素,或者可以用一个变量把元素弹栈保存后再压栈)
public void postOrderTraverse() //后根次序遍历二叉树的非递归算法
{
System.out.print("后根次序遍历(非递归): ");
LinkedStack<BinaryNode<T>> stack = new LinkedStack<BinaryNode<T>>();
BinaryNode<T> p=this.root, front=null;
while (p!=null || !stack.isEmpty()) //p非空或栈非空时
if (p!=null)
{
stack.push(p); //p结点入栈
p=p.left; //进入左子树
}
else //p为空且栈非空时
{
p=stack.get(); //从左子树返回p结点,p结点不出栈
if (p.right!=null && p.right!=front) //p有右孩子,且右孩子没被访问过
{
p = p.right; //进入右子树
stack.push(p);
p=p.left; //向左走
}
else
{
p=stack.pop(); //从右子树返回p结点,p结点出栈
System.out.println(p.data+"的所有祖先结点是:"+stack.toString());
front = p; //front是p在后根遍历次序下的前驱结点
p=null;
}
}
System.out.println();
}
层次遍历(每一层地访问)
非递归用队列实现,类似于广度优先搜索
public void levelOrder(){ //层序遍历,非递归
System.out.print("层序遍历二叉树:");
Queue<BinaryNode> queue = new LinkedList<BinaryNode>(); //LinkedList类实现了Queue接口
BinaryNode<T> p=this.root;
while (p!=null){
System.out.print(p.data.toString()+" ");//访问当前结点
if (p.left!=null)
queue.offer(p.left); //p的左孩子入队,add方法也可以入队,但失败时会抛出异常
if (p.right!=null)
queue.offer(p.right); //p的有孩子入队
p=queue.poll(); //p指向出队结点,若队列空,则返回null
}
System.out.println();
}
二叉树的结点类
class BinaryNode<T extends Comparable<? super T>>{ // T继承Comparable类
public T data;
public BinaryNode<T> left;
public BinaryNode<T> right;
public BinaryNode(T data,BinaryNode<T> left,BinaryNode<T> right){
this.data=data;
this.left=left;
this.right=right;
}
public BinaryNode(T data){
this(data,null,null);
}
public String toString(){
return this.data.toString();
}
public boolean isLeaf(){
return this.left==null && this.right==null;
}
}
以上源码均经过测试没有错误,用笔画画图会更好理解,如果有错误的欢迎在评论区指正。