二叉树的遍历(递归与非递归实现)
二叉树的实现(三叉链表的形式)
public class XieChaoThreeLinkBinTree<E> {
public static class TreeNode<T>
{
T data;
TreeNode<T> left;
TreeNode<T> right;
TreeNode<T> parent;
public TreeNode(){ }
public TreeNode(T data)
{
this.data=data;
}
public TreeNode(T data, TreeNode<T> left, TreeNode<T> right, TreeNode<T> parent) {
this.data = data;
this.left = left;
this.right = right;
this.parent = parent;
}
public TreeNode(T data, TreeNode<T> left, TreeNode<T> right)
{
this.data=data;
this.left=left;
this.right=right;
}
}
TreeNode<E> root;
public XieChaoThreeLinkBinTree(){
root= new TreeNode<E>();
}
public XieChaoThreeLinkBinTree(E data)
{
this.root=new TreeNode<>(data);
}
public XieChaoThreeLinkBinTree(TreeNode<E> root){
this.root=root;
}
public TreeNode<E> addTreeNode(TreeNode<E> parent,E data, boolean isLeft) {
if (null == parent)
throw new RuntimeException("节点为空,无法插入子节点");
if (isLeft && parent.left != null)
throw new RuntimeException(parent + "节点已经有了左节点,无法继续插入");
if (!isLeft && parent.right != null)
throw new RuntimeException(parent + "节点已有了右节点,无法继续插入");
TreeNode<E> node=new TreeNode<>(data,null,null,parent);
if (isLeft)
{
parent.left=node;
}
else{
parent.right=node;
}
return node;
}
public boolean empty()
{
return root==null;
}
public TreeNode<E> root()
{
return this.root;
}
public E parent(TreeNode<E> root)
{
if(null == root)
throw new RuntimeException("节点为null,无法访问其父节点");
return root.parent.data;
}
public E leftChild(TreeNode<E> root)
{
if( null == root)
throw new RuntimeException("节点为空,无法访问其子节点");
return root.left == null?null:root.left.data;
}
public E rightChild(TreeNode<E> root)
{
if( null == root)
throw new RuntimeException("节点为空,无法访问其子节点");
return root.right == null?null:root.right.data;
}
public int deep()
{
return deep(root);
}
private int deep(TreeNode<E> root) {
if(null == root )
return 0;
if(null == root.left && null==root.right)
return 1;
return Math.max(deep(root.left),deep(root.right))+1;
}
}
一.递归
前序遍历:
public void PreOrderTraverse(TreeNode<E> root){
if(null == root)
return;
System.out.print(root.data+" ");
PreOrderTraverse(root.left);
PreOrderTraverse(root.right);
}
中序遍历:
public void InOrderTraverse(TreeNode<E> root)
{
if(null == root)
return;
InOrderTraverse(root.left);
System.out.print(root.data+" ");
InOrderTraverse(root.right);
}
后续遍历:
if(null == root)
return;
PostOrderTraverse(root.left);
PostOrderTraverse(root.right);
System.out.print(root.data+" ");
非递归方式:
1.前序遍历(深度优先遍历):借助栈,右孩子先于左孩子入栈,后语左孩子出栈。
public void PreOrderTraverseByStack(TreeNode<E> root)
{
if( null == root)
return;
Stack<TreeNode<E>> stack=new Stack<>();
stack.push(root);
while(!stack.empty())
{
TreeNode<E> node=stack.pop();
if(null != node.right)
stack.push(node.right);
if(null != node.left)
stack.push(node.left);
}
}
2.中序遍历:栈
public void InOrderTraverseByStack(TreeNode<E> root)
{
Stack<TreeNode<E>> stack=new Stack<>();
TreeNode<E> node=root;
while(!stack.empty()|| null!=node)
{
while(null !=node )
{
stack.push(node);
node=node.left;
}
if(stack != null)
{
node=stack.pop();
System.out.print(node.data+" ");
node=node.right;
}
}
}
3.后序遍历:后序遍历是最难的,也是借助栈。
思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一个结点P,先将其入栈,如果P不存在左孩子和右孩子,可以直接访问它。或者P存在左孩子或者右孩子,但其左孩子和右孩子都已经被访问过了(已经出栈了),则同样可以访问此P结点。
总结一下思路:
1)对于任意个结点P,首先需要将其入栈
2)如果P没有左孩子也没有右孩子,或者有左孩子或者右孩子,但是左右孩子已经被输出了,那么就可以把该结点直接进行输出,并将其出栈。将出栈的结点定义为上一个结点(pre=cur),并把当前栈顶的元素重新置为当前结点(cur=s.peek())。
3)如果不满足2)的条件,则将其右孩子左孩子入栈。当前结点重新置为栈顶结点,然后重复2)
4)直至栈顶为空,然后遍历结束。
设计思路:设置两个指针,cur指向当前栈顶节点,为当前节点。
pre为上一个访问的节点,上一个出栈的节点。
public void PostOrderTraverseByStack(TreeNode<E> root)
{
Stack<TreeNode<E>> stack=new Stack<>();
TreeNode<E> cur;
TreeNode<E> pre=null;
stack.push(root);
while(!stack.empty()){
cur=stack.peek();
if((cur.left == null && cur.right ==null)||(pre !=null &&(pre.parent == cur)))
{
System.out.print(cur.data+" ");
stack.pop();
pre=cur;
}else{
if(null != cur.right)
stack.push(cur.right);
if(null != cur.left)
stack.push(cur.left);
}
}
}
4.层序遍历(广度优先遍历):借助队列
public void LayerOrderTraverse(TreeNode<E> root)
{
Queue<TreeNode<E>> queue=new LinkedList<TreeNode<E>>();
if(null !=root){
queue.offer(root);
}
while(!queue.isEmpty())
{
TreeNode<String> node= (TreeNode<String>) queue.poll();
System.out.print(node.data+" ");
if(null !=node.left)
queue.offer((TreeNode<E>) node.left);
if(null !=node.right)
queue.offer((TreeNode<E>) node.right);
}
}