树的遍历(个人版)

因为学得太烂以至于忘掉了老师上课讲的具体步骤。。。/(ㄒoㄒ)/~~

然后作业又要求写,只好自己写了

最后发现除了层序遍历,其它几个都是用栈实现的

还有:

    今天才知道,原来

    就算你新建了一个树类并赋值为原来的树,他喵的还是按传址处理原来的树类

    于是就导致主方法写得很奇葩

    好像整个过程就写得很奇葩好伐。。。┑( ̄Д  ̄)┍

  


package BianLi;

public class Quee {
	Node head,tail;
	Node pointer;
	Object value;
	int size;
	public Quee(){
		head=new Node();
		tail=head;
		size=0;
	}
	public void  InQuee(Node node)
	{
		tail.LinkNext(node);
		tail=node;
		size++;
	}
	public Node OutQuee()
	{
		if(size>0)
		{
		  if(size==1)
		  {
			  Node n=head.next();
			  head.LinkNext(null);
			  size--;
			  return n;
		  }
		  else
		  {
			  Node n=head.next();
			  head.LinkNext(n.next());
			  //head.next().LinkNext(null);  不知道错在哪里,辣眼睛
			  size--;
			  return n;
			  
		  }
		  
		}
		else
		{
			System.out.println("队列是空的");
			return null;
		}
	}
 public boolean IsEmpty()
 {
	 if(size==0) return true;
	 else return false;
 }

}
class Node
{
	Node next;
	Object value;
	boolean ifprint;
	public Node(){}
	public Node (Object value)
	{
		this.value=value;
		ifprint=false;
	}
    public Node next()
    {
    	return this.next;
    }
    public void LinkNext(Node node)
    {
    	this.next=node;
    }
    public Object getValue()
    {
    	return this.value;
    }
    Node left,right,father;
	//左子结点
	public void LinkLeftLeaf(Node left)
	{
		this.left=left;
	}
	public Node getLeftLeaf()
	{
		return this.left;
	}
	//右子结点
	public void LinkRightLeaf(Node right)
	{
		this.right=right;
	}
	public Node getRightLeaf()
	{
		return this.right;
	}
	//父节点
	public void LinkFather(Node father)
	{
		this.father=father;
	}
	public Node getFather()
	{
		return this.father;
	}
	
}

package BianLi;

public class Stack {
   Node top;
   Node bottom;
   Node pointer;
   int size=0;
   public Stack()
   {
	   top=new Node();
	   bottom=top;
	   pointer=top;
	   size=0;
   }
   public void InStack(Node node)
   {
	 top.LinkNext(node);
	 top=node;
	 size++;
   }
   public Node OutStack()
   {
	 if(size>0)
	 {
	   Node n=top;
	   pointer=bottom;
	   while(pointer.next()!=top)
		   pointer=pointer.next();
	   pointer.LinkNext(null);
	   top=pointer;
	   size--;
	   return n;
	 }
	 else 
		 {
		  System.out.println("栈是空的");
		   return null;
		 
		 }
   }
   
}
package BianLi;

public class TreeClass {
	Node root;//根结点
	Object value;
	public TreeClass(Node root)
	{
		this.root=new Node();
		this.root=root;
	}
	//添加左子结点
	public void AddLeftLeaf(Node left)
	{
		root.LinkLeftLeaf(left);
		left.LinkFather(root);
	}
	//添加右子节点
    public void AddRightLeaf(Node right)
    {
    	root.LinkRightLeaf(right);
    	right.LinkFather(root);
    }
    //判断父节点是否有子节点
    public boolean HaveChild(Node root)
    {
    	boolean have=true;
    	if((root.getLeftLeaf()==null)&&(root.getRightLeaf()==null)) have=false;
    	return have;
    	
    }
    //层序遍历:利用队列,从根节点开始入队
    public void LevelOrder()
    {
     	Quee q =new Quee();
     	q.InQuee(root);
     	System.out.println("层序遍历是:");
     	while(q.size>0)
     	{
     		root=q.head.next();
     		if(HaveChild(root))//添加父节点的所有孩子
     		{
     			if(root.getLeftLeaf()!=null) 
     				{
     				  q.InQuee(root.getLeftLeaf());
     				}
     			if(root.getRightLeaf()!=null)
     			{
     				q.InQuee(root.getRightLeaf());
     			}
     		}
     		System.out.print(q.OutQuee().getValue());
     	}
    }
    /*后序遍历:用栈储存
                   如果有左子树,一直找到没有左子树为止
                  否则找右子树
                  如果发现已经找到底(没有左子树和右子树)那么开始出栈,根节点退回上一节点
     */ 
    public void PostOrder()
    {
    	Stack s=new Stack();
    	s.InStack(root);
    	System.out.println("后序遍历是:");
    	while(s.size>0)
    	{
    	   if(root.getLeftLeaf()!=null)
    		  while(root.getLeftLeaf()!=null)
    		  {
    			s.InStack(root.getLeftLeaf());
    			Node n=root.getLeftLeaf();
    			root.LinkLeftLeaf(null);//为了防止出栈退回节点时发生死循环,找到子节点后从树上删掉父节点与子节点的连接
    			root=n;
    		  }
    	   else if(root.getRightLeaf()!=null)
    	   {
    		   s.InStack(root.getRightLeaf());
    		   Node n=root.getRightLeaf();
   			   root.LinkRightLeaf(null);
   			root=n;
    	   }
    	   else
    	   {
    		System.out.print(s.OutStack().getValue()); 
    		root=s.top;
    	   }
    	}
    }
    /*
                   前序遍历:和后序遍历有区别的是,在输出的时候因为先输出的是根节点的值但根节点又不能出栈,所以要设置一个
                   参照判断根节点有没有被输出过
                   然后再依次让左右子节点依次入栈并成为新的根节点
     */
public void PreOrder()
{
	Stack s=new Stack();
	s.InStack(root);
	System.out.println("前序遍历是:");
	while(s.size>0)
	{
		if(root.ifprint==false)
		{
			System.out.print(root.getValue());
			root.ifprint=true;
		}
	   if(root.getLeftLeaf()!=null)
		  {
			s.InStack(root.getLeftLeaf());
			Node n=root.getLeftLeaf();
			root.LinkLeftLeaf(null);
			root=n;
		  }
	   else if(root.getRightLeaf()!=null)
	   {
		   s.InStack(root.getRightLeaf());
		   Node n=root.getRightLeaf();
			   root.LinkRightLeaf(null);
			root=n;
	   }
	   else
	   {
		s.OutStack(); 
		root=s.top;
	   }
	}
  }
/*
 * 中序遍历:中序遍历与先前的稍有差异
 * 虽然也是一路找到左子结点到底为止,但是应该注意;
 * 当左子节点没有了的时候应该先输出根节点然后再操作右结点
 * 同样的,每次操作后,下一个被遍历的子节点称为新的根节点
 * 当然,当到底的时候应该从栈里弹出
 */
public void InOrder()
{
	Stack s=new Stack();
	s.InStack(root);
	System.out.println("中序遍历是:");
	while(s.size>0)
	{
	   if(root.getLeftLeaf()!=null)
		  while(root.getLeftLeaf()!=null)
		  {
			s.InStack(root.getLeftLeaf());
			Node n=root.getLeftLeaf();
			root.LinkLeftLeaf(null);
			root=n;
		  }
	   else if(root.getRightLeaf()!=null)
	   {
		 
            System.out.print(root.getValue());
            root.ifprint=true;
		   s.InStack(root.getRightLeaf());
		   Node n=root.getRightLeaf();
			   root.LinkRightLeaf(null);
			root=n;
	   }
	   else
	   {
			if(root.ifprint==false)
				{
				System.out.print(s.OutStack().getValue()); 
				root.ifprint=true;
				}
			else
			{
				s.OutStack();
			}
		
		root=s.top;
	   }
	}
}
}

package BianLi;

public class MainMethod {
	public static void main(String[] args)
	{
	
 //建立好二叉树
  Node leaf1=new Node('+');
  Node leaf2=new Node('A');
  Node leaf3=new Node('/');
  Node leaf4=new Node('*');
  Node leaf5=new Node('D');
  Node leaf6=new Node('B');
  Node leaf7=new Node('C');
  TreeClass tree=new TreeClass(leaf1);
  tree.AddLeftLeaf(leaf2);
  tree.AddRightLeaf(leaf3);
  tree.root=leaf3;
  tree.AddLeftLeaf(leaf4);
  tree.AddRightLeaf(leaf5);
  tree.root=leaf4;
  tree.AddLeftLeaf(leaf6);
  tree.AddRightLeaf(leaf7);
  tree.root=leaf1;
  tree.LevelOrder();
  System.out.println();
  tree.root=leaf1;
  TreeClass treepost=new TreeClass(leaf1);
  treepost=tree;
  treepost.PostOrder();
  System.out.println();
  TreeClass treepre=new TreeClass(leaf1);
  treepre.AddLeftLeaf(leaf2);
  treepre.AddRightLeaf(leaf3);
  treepre.root=leaf3;
  treepre.AddLeftLeaf(leaf4);
  treepre.AddRightLeaf(leaf5);
  treepre.root=leaf4;
  treepre.AddLeftLeaf(leaf6);
  treepre.AddRightLeaf(leaf7);
  treepre.root=leaf1;
  treepre.PreOrder();
  System.out.println();
  leaf1.ifprint=false;
  leaf2.ifprint=false;
  leaf3.ifprint=false;
  leaf4.ifprint=false;
  leaf5.ifprint=false;
  leaf6.ifprint=false;
  leaf7.ifprint=false;
  TreeClass treein=new TreeClass(leaf1);
  treein.AddLeftLeaf(leaf2);
  treein.AddRightLeaf(leaf3);
  treein.root=leaf3;
  treein.AddLeftLeaf(leaf4);
  treein.AddRightLeaf(leaf5);
  treein.root=leaf4;
  treein.AddLeftLeaf(leaf6);
  treein.AddRightLeaf(leaf7);
  treein.root=leaf1;
  treein.InOrder();
	} 
}

运行结果:

层序遍历是:
+A/*DBC
后序遍历是:
ABC*D/+
前序遍历是:
+A/*BCD
中序遍历是:
A+B*C/D

突然发现是按照老师上课讲的写的,只不过写成了鬼畜版(QAQ)

 中根遍历非递归算法

    1. 建立栈结构,建立一个节点作为当前节点

    2. 如果当前节点非空或者栈非空,重复执行3-5步

    3. 重复执行这样操作:如果当前节点非空,便将其压入栈中,并让当前节点访问当前节点的左子节点,直到当前节点再无左节点

    4. 如果栈非空,则访问栈顶节点并出栈

    5. 当前节点变为出栈节点的右子节点


 先根遍历非递归算法   

    1. 建立栈结构,建立当前节点

    2. 如果当前节点非空或者栈非空,重复执行3-5步

    3. 重复执行这样操作:如果但前节点非空,访问当前节点,并将其压入栈中,并让当前节点访问当前节点的左子节点,直到当前节点再无左节点

    4. 如果栈非空,则栈顶出栈

    5. 当前节点变为出栈节点的右子节点


后根遍历非递归算法   

   1.建立栈结构,建立当前节点,建立当前节点的前一次访问节点
   2.根节点压栈
   3.如果栈非空,重复4-6步
   4.当前节点为栈顶节点
   5.如果当前节点没有子节点或子节点在上一步已经被访问过
     •则 访问当前节点,栈顶出栈,并记录前一次访问节点为当前节点。
   6.否则
     •如果当前节点有右子节点,则 右子节点压栈
     •如果但前节点有左子节点,则 左子节点压栈


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值