二叉树的遍历实现-1(三级)

package com.learn.btree;

/**
 * 二叉链表的节点
 * @author Leon.Sun
 *
 */
public class Node {

	/**
	 * 节点的值
	 */
	// private Object value;
	Object value;
	
	/**
	 * 左孩子
	 * 左子树的引用
	 * 同样为了处理方便,我们把private去掉
	 */
	// private Node leftChild;	
	Node leftChild;
	
	/**
	 * 右子树的引用
	 */
	// private Node rightChild;
	Node rightChild;

	public Node() {
		super();
	}
	
	public Node(Object value) {
		super();
		this.value = value;
	}

	public Node(Object value, Node leftChild, Node rightChild) {
		super();
		this.value = value;
		this.leftChild = leftChild;
		this.rightChild = rightChild;
	}

	/**
	 * 这个toString该怎么写呢
	 * 输出三个属性的值就可以了
	 */
	@Override
	public String toString() {
		return "Node [value=" + value + ", leftChild=" + leftChild + ", rightChild=" + rightChild + "]";
	}
	
}
package com.learn.btree;

/**
 * 二叉树接口
 * 可以有不同的实现类,每个类可以使用不同的存储结构,比如顺序结构、链式结构
 * 链式结构可以是二叉的,也可以是三叉的
 * @author Leon.Sun
 *
 */
public interface BinaryTree {
	/**
	 * 是否空树
	 * 你的树是空的吗,空是什么意思
	 * 有没有根节点,有根就不是空的了
	 * @return
	 */
	public boolean isEmpty();
	/**
	 * 树结点数量
	 * 树里面有几个节点
	 * @return
	 */
	public int size();
	
	/**
	 * 获取二叉树的高度
	 * 得到树的高度
	 * @return
	 */
	public int getHeight();
	/**
	 * 查询指定值的结点
	 * 在树里面去找一个值
	 * 我去找20,要告诉我这里没有20才可以
	 * @param value
	 * @return
	 */
	public Node findKey(int value); // 查找
	/**
	 * 前序递归遍历
	 * 这三个遍历要采用递归来实现
	 */
	public void preOrderTraverse(); 
	/**
	 * 中序遍历递归操作
	 */
	public void inOrderTraverse();  	
	/**
	 * 后序遍历递归操作
	 */
	public void postOrderTraverse();
	/**
	 * 后序遍历递归操作
	 * 这个是重载,一个有参,一个无参
	 * @param node  树根结点
	 */
	public void postOrderTraverse(Node node); 
	/**
	 * 中序遍历非递归操作
	 * 1)对于任意节点current,若该节点不为空则将该节点压栈,并将左子树节点置为current,重复此操作,直到current为空。 
	 * 2)若左子树为空,栈顶节点出栈,访问节点后将该节点的右子树置为current
	 * 3) 重复1、2步操作,直到current为空且栈内节点为空。 
	 */
	public void inOrderByStack();
	/**
	 *   前序遍历非递归操作
	 *   1)对于任意节点current,若该节点不为空则访问该节点后再将节点压栈,并将左子树节点置为current,重复此操作,直到current为空。 
	 *   2)若左子树为空,栈顶节点出栈,将该节点的右子树置为current 
	 *   3) 重复1、2步操作,直到current为空且栈内节点为空。
	 */
	public void preOrderByStack(); 
	/**
	 * 后序遍历非递归操作
	 * 1)对于任意节点current,若该节点不为空则访问该节点后再将节点压栈,并将左子树节点置为current,重复此操作,直到current为空。 
	 * 2)若左子树为空,取栈顶节点的右子树,如果右子树为空或右子树刚访问过,则访问该节点,并将preNode置为该节点 
	 * 3) 重复1、2步操作,直到current为空且栈内节点为空。 
	 */
	public void postOrderByStack(); 
	
	/**
	 * 按照层次遍历二叉树
	 * 这个需要借助队列来实现,这里还是包含很多技能点的
	 */
	public void levelOrderByStack();
}
package com.learn.btree;

/**
 * 他要实现一下2我们的BinaryTree,要实现这个接口
 * 你把这些方法掌握了,那二叉树的基本操作呢就基本上知道了
 * 但不是所有的操作,基本操作都知道了
 * 这是一个链式二叉树的实现类
 * 
 * 这个类里面我们做一个操作,
 * @author Leon.Sun
 *
 */
public class LinkedBinaryTree implements BinaryTree {
	
	/**
	 * 根节点
	 */
	private Node root;
	
	/**
	 * 我每次增加一个节点的时候他就加1
	 * 但是为什么我们目前没有写size,
	 * 因为目前没有增加的方法,
	 * 我们创建这棵树,是直接做的,
	 * 当然还有简单的方法,创建这棵树时候,你把7传进来
	 * 但是这么做也没有什么技术含量,这个size我们每次=求就可以了
	 */
	// private int size;
	
	/**
	 * 然后我们再给他提供一个构造方法
	 */	
	public LinkedBinaryTree(Node root) {
		super();
		this.root = root;
	}
	
	public LinkedBinaryTree() {
		super();
	}

	/**
	 * 这里永远返回false,
	 * 怎么样这棵树才是空的呢,树是空的,一个节点也没有
	 */
	@Override
	public boolean isEmpty() {
		/**
		 * 就是root等于null
		 * 如果root等于的话他就是一个空的树
		 */
		return root==null;
	}

	/**
	 * 我们的这个size该怎么办,
	 */
	@Override
	public int size() {
		System.out.println("二叉树节点的个数: ");
		
		/**
		 * 你想一下他的数量应该是多少
		 * 你怎么知道他的结构是7呢,
		 * 因为左边是2,右边是4,
		 * 整个就是2+4+根1等于7
		 * 你怎么知道这个是4呢,
		 * 左边是1,右边是2,再加上根1,等于4
		 * 你怎么知道这个是2呢,
		 * 左边是0,右边是1,再加上这个根1,等于2
		 * 你怎么知道7是1呢,
		 * 左边是0,右边是0,再加上1等于1
		 * 好像和我们刚才求高度是一样的
		 * 只不过高度里面是求两个里面最大的树
		 * 我们现在是两个数相加
		 * 
		 */
		return this.size(root);
	}
	
	/**
	 * 这里还是写成private不对外公布了
	 * 这里面要写一个Node,
	 * 写Node root吧,root可读性强
	 */
	private int size(Node root) {
		
		/**
		 * 如果root等于null还是返回0
		 */
		if(root==null) {		
			return 0;
		}else {
			/**
			 * 获取左子树的size
			 */
			int nl = this.size(root.leftChild);
			
			/**
			 * 获取右子树的size
			 */
			int nr = this.size(root.rightChild);
			
			/**
			 * 返回的是谁,
			 * 返回的是nl+nr+1
			 * 返回左子树右子树size只和再加1
			 */
			return nl+nr+1;			
		}
	}
	/**
	 * 二叉树的高度
	 */
	@Override
	public int getHeight() {
		/**
		 * 我们在这里输出一句话来
		 */
		System.out.println("二叉树的高度是: ");
		
		/**
		 * return这个值,
		 * 这个值怎么办,和刚才一样提供一个辅助的方法
		 */
		return this.getHeight(root);
	}
	
	/**
	 * 提供一个辅助的方法
	 * 这边传入一个Node root
	 * @param root
	 * @return
	 */
	private int getHeight(Node root) {
		/**
		 * 首先是有前提条件的,root不能等于null
		 * 如果root不等于null我们就做这个事了
		 */
		if(root==null) {		
			/**
			 * 如果root等于null了
			 * 那就return o呗
			 * 递归要有一个结束条件
			 */
			return 0;
		}else {
			/**
			 * 获取左子树的高度
			 * 
			 * 得到一个值,
			 * 这里是l不是1,
			 */
			int nl = this.getHeight(root.leftChild);
			
			/**
			 * 获取右子树的高度
			 */
			int nr = this.getHeight(root.rightChild);
			
			/**
			 * 返回谁,返回左子树,右子树较大高度并加1
			 * 
			 * 最后返回谁
			 * 如果nl大于nr就返回nl加1
			 * 如果nl小于nr就返回nr加1
			 * 你看又是递归,也不怎么复杂
			 */
			return nl>nr ? nl+1 : nr+1;			
		}
		
	}

	@Override
	public Node findKey(int value) {
		return null;
	}

	/**
	 * 先序 遍历分几步,分三步
	 */
	@Override
	public void preOrderTraverse() {
		/**
		 * 输出根节点的值
		 * 我们只要value的值1,
		 * 这样1就出来了
		 * 这是有条件的,如果root要是等于空呢,
		 * 空节点你就别输出了,这也算递归的一个结构条件
		 * 
		 * 我们只要简单的变一下就可以了,把这里的ln去了
		 */
		if(root!=null) {			
			System.out.print(root.value + " ");
			
			/**
			 * 对左子树进行先序遍历
			 * 左边玩不了就不会走右边
			 * 
			 * 对做子树进行遍历怎么办
			 * 这跟左也没有关系啊,
			 * 
			 * 如果root不等于null,创建做子树
			 * 
			 */
			if(root.leftChild!=null) {
				/**
				 * 创建左子树,左子树本来就是存在的
				 * 对做子树进行先序遍历
				 * 构建一个二叉树,根是左子树的根
				 * 拿着root.leftChild做根
				 */
				BinaryTree leftTree = new LinkedBinaryTree(root.leftChild);
				
				/**
				 * 拿着左子树,4做根,
				 * 这是一颗二叉树了,对它进行遍历
				 * 对root.leftChild进行遍历
				 * 对左子树进行先序遍历
				 */
				leftTree.preOrderTraverse();
			}
			
			/**
			 * 对右子树进行先序遍历
			 * 只要这三步就可以
			 * 
			 * preOrderTraverse这跟右子树也没有关系,
			 * 什么左子树什么右子树,this是当前这棵树
			 * 他找的是当前这棵树,当前这棵树是谁啊,
			 * 就是btree,你这么来做的话可能会死循环了,
			 * 
			 * 但是你这么写的话代码有点繁琐,条件都是一样的,
			 */
			if(root.rightChild!=null) {
				BinaryTree rightTree = new LinkedBinaryTree(root.rightChild);
				rightTree.preOrderTraverse();
			}
		}
		
	}

	/**
	 * 这里面怎么办,
	 */
	@Override
	public void inOrderTraverse() {
		/**
		 * 再调用一个方法,不管别的我先输出一个中序遍历
		 */
		System.out.println("中序遍历");
		
		/**
		 * 第一次调用的时候是不是需要把整个二叉树的根传进去
		 * 是不是有参数的,它是对整个树进行二叉遍历的
		 */
		this.inOrderTraverse(root);
		
		/**
		 * 输出换行
		 */
		System.out.println();
	}
	
	/**
	 * 我们拿过来复制一下,这个方法是辅助的
	 * 可以不对外开发,直接写成private
	 * 传一个Node root
	 * 这个是不是有根啊
	 * 
	 * 我再提供一个辅助的方法,还要传参
	 * 开发者考虑这些就可以了,然后再递归调用
	 * 说来说去还要看结果的运行,
	 * 别到时运行结果是错的那就不好了
	 */
	private void inOrderTraverse(Node root) {
		/**
		 * 再调用一个方法
		 * 如果root不等于null做三件事
		 * 
		 * 三条语句加一个判断,就可以了
		 * 是不是都用到了递归,我们体会到递归的强大之处
		 */
		if(root!=null) {			
			/**
			 * 遍历左子树
			 * 怎么遍历左子树,这里面本来就有参数
			 * 
			 * 你知道你调用inOrderTraverse(root.leftChild)
			 * 这句话意味着什么吗,刚开始root传的是谁,传的是1,
			 * 下一份传的是谁啊,相当于拿着4作为根了去遍历一下
			 * 递归要用了,调了好多次了,到了叶子的时候还要调,当我你们拿到7做根的时候
			 * 拿到node7做根了,如果我拿到node7做根,传了node7叶子节点
			 * node7不等于空,所以对他的左子树进行遍历,左子树这个时候已经是null了
			 * 
			 */
			if(root.leftChild!=null) {				
				this.inOrderTraverse(root.leftChild);
			}
			
			/**
			 * 输出根的值
			 * 输出他的值,他的值是7
			 */
			System.out.print(root.value + " ");
			
			/**
			 * 遍历右子树,右子树也是null了,
			 */
			if(root.rightChild!=null) {
				this.inOrderTraverse(root.rightChild);
			}
		}
		
		
	}

	@Override
	public void postOrderTraverse() {
		/**
		 * 输出一下后序遍历
		 */
		System.out.println("后序遍历");
		
		/**
		 * 第一次调用是root的根
		 */
		this.postOrderTraverse(root);
		
		/**
		 * 输出玩之后再来一个换行
		 */
		System.out.println();
		
		
	}
	
	/**
	 * 我们再提供一个辅助的方法,这个辅助方法可以不对外面的调用者开发
	 * 这里面要传一个参数,但是这个root是谁不确定,这个方法本来就有了
	 * 有了我就直接用它了
	 */
	@Override
	public void postOrderTraverse(Node node) {
		/**
		 * 如果node等于null,
		 * 
		 * 这里不是root了,而是node了,
		 */
		if(node!=null) {
			/**
			 * 后序遍历该怎么办
			 * 遍历左子树
			 */
			if(node.leftChild!=null) {
				/**
				 * 左孩子当做一个棵树来遍历
				 */
				this.postOrderTraverse(node.leftChild);
			}
			
			/**
			 * 遍历右子树
			 */
			if(node.rightChild!=null) {
				this.postOrderTraverse(node.rightChild);
			}
			
			/**
			 * 输出根的值
			 * 先写这一个
			 * 不加ln,加个空格
			 */
			System.out.print(node.value + " ");			
		}
	}

	@Override
	public void inOrderByStack() {
		
	}

	@Override
	public void preOrderByStack() {
		
	}

	@Override
	public void postOrderByStack() {
		
	}

	@Override
	public void levelOrderByStack() {
		
	}

}
package com.learn.btree;

/**
 * 在这个测试类里面我们要干什么,
 * 这是一个测试类,我们按照这些功能依次来实现
 * @author Leon.Sun
 *
 */
public class Test {

	public static void main(String[] args) {
		/**
		 * 你想进行遍历,我想遍历一下这个数
		 * 我想看看这个数一共有几层,前提是创建一个二叉树
		 * 怎么来创建一个二叉树呢,就把这个二叉树创建起来,
		 * 那该怎么办呢,一个节点一个节点的创建出来,然后指明他们的关系不就可以了吗
		 * 从叶子开始吧,从5开始,Node5是不是有构造方法,告诉我他的值是多少
		 * 值是5,左右都没有,这是5了,
		 */
		Node node5 = new Node(5,null,null);
		
		/**
		 * 再来创建一个4呗
		 * 值是多少,值是4,左孩子没有,右孩子是node5
		 * 是不是指向他啊,这么久成了
		 */
		Node node4 = new Node(4,null,node5);
		
		/**
		 * node3也是叶子节点
		 */
		Node node3 = new Node(3,null,null);
		
		/**
		 * 下面从7开始吧
		 * 7是叶子节点,那左右都是null
		 * 值是7
		 */
//		 Node node7 = new Node(7,null,null);
		
		/**
		 * node6,值是6,左孩子没有,右孩子是node7
		 */
//		Node node6 = new Node(6,null,node7);
		
		/**
		 * node6就变成叶子了
		 */
		Node node6 = new Node(6,null,null);
		
		/**
		 * 2还没有呢,怎么办,
		 * node2值是2,左是node3,右是node6
		 */
		Node node2 = new Node(2,node3,node6);
		
		/**
		 * 最后还差一个node1,值是1
		 * 左边指向的是node4,右边指向的是node2
		 * 我们相当于把一棵树给搭建好了
		 * 但是搭建好了之后和LinkedBinargyTree没有一点关系
		 * 好像只是把这些节点按照一定的规则排到一起了,你下边还要做一件事
		 * 这棵树你得知道根是谁,只要我们能够找到根,基本上就可以找到别的节点
		 */
		Node node1 = new Node(1,node4,node2);
		
		/**
		 * 怎么把我们搭建的一大堆变成一棵树呢,跟我们的类发生关联
		 * BinaryTree接口,把node1传进去
		 * 这么一棵树就搭建好了,这个也太没有技术含量了吧
		 * 如果有100个节点的话,我们要加100棵树吗,
		 * 因为我们这棵树是没有特点的,他没有说左边的小右边的大
		 * 值是不是没有规律的,比如我们学过集合了,是不是学过TreeSet,
		 * 人家里面的树都是有序的,左边的永远小于根,根永远小于右边的,
		 * 人家都是递归定义的,这种情况下你随便给个值,不需要我们拼接这个数
		 * 这个大家知道,
		 */
		BinaryTree btree = new LinkedBinaryTree(node1);
		
		/**
		 * 比如我们把这个语句复制一份,我这里没有传这个根过去
		 * 是不是空的二叉树一个节点也没有,他就是一颗空数组
		 * 二叉树我们已经实现两个操作了,创建二叉树没有多大含量
		 * 
		 * 我们试一个特殊的情况,这什么意思啊
		 * 创建了一个二叉树,他是一个空的
		 * 那他的节点数量是0,所以我们有时候写代码的时候要健壮
		 * 某些边界值一定要考虑到,看我们的代码是不是完善
		 * 这是0的,
		 */
//		 BinaryTree btree = new LinkedBinaryTree();
		
		/**
		 * 判断二叉树是否为空,这个简单
		 * 判断二叉树是否为空这个怎么办,输出一下呗
		 */
		System.out.println(btree.isEmpty());
		
		System.out.println("先序遍历:");
		/**
		 * 先序遍历递归
		 * 什么叫先序遍历,preOrderTraverse这个就是先序遍历
		 * 先序遍历的结果是多少,1452367
		 * 
		 * 但是还是不满意,main方法是调用者来写的,
		 * 能不能我就调用一个方法,你把所有的事情都给我做了
		 * 这是增加测试者的负担,还要创建一个左子树和右子树,
		 * 分别进行遍历,我们针对这个做一些改进,
		 */
		btree.preOrderTraverse();
		
		System.out.println();
		System.out.println("中序遍历:");
		/**
		 * 中序遍历递归
		 * 中序遍历的结果是这个:4513267
		 * 结果必须对,中序遍历你只需要做一件事
		 * 这一句话就够了,有人说你这一句话不太对
		 * 因为你这里也没有传任何值
		 * 
		 * 外层不需要传任何的参数,调这个方法就可以了,
		 * 所有的细节在这里都可以搞定,
		 */
		btree.inOrderTraverse();
		
		/**
		 * 后序遍历递归
		 * 后序遍历:5437621
		 * 
		 * 到这里我们就把先序中序后序遍历都给写出来了
		 * 刚开始怎么办,刚开始我们写了一个比较复杂的,
		 * 
		 */
		btree.postOrderTraverse();
		
		/**
		 * 中序遍历非递归
		 * 中序遍历如果采用非递归的遍历
		 * 需要借助栈
		 * 
		 * 我们再实现一个功能,这个非递归的我们先等一等吧
		 * 我们先看一下别的
		 */
		
		/**
		 * 按照层次遍历,借助队列
		 * 先把这些层次记住
		 */
		
		/**
		 * 在二叉树中查找某个值
		 */
		
		/**
		 * 二叉树的高度,他总共有几层
		 * 
		 * 二叉树的高度是几啊你觉得,
		 * 我要得到这棵树的高度,这个该怎么写
		 * 这棵树的高度是4,4层,我怎么知道这棵树的高度是4
		 * 要用递归,这和递归有关系吗,递归,树的高度就这么来
		 * 整棵树的高度是4,我怎么知道是4,先看他左子树的高度是几
		 * 目前是2,左子树是两层,是2,右子树的高度是几,是3,
		 * 左子树的高度是2,右子树的高度是3,从里面选一个大的,是3
		 * 别忘了,还有一个根呢,根是几,根是1,3+1=4
		 * 有人说你怎么知道右子树是3,左子树这个是1,这个高度是2
		 * 左子树是1,右子树是2,两个里面找一个大的是几,是2
		 * 再加上这个根加1,是不是等于3,这好像还是递归,
		 * 你怎么知道67这棵树的高度是2呢,因为左子树是0,右子树是1
		 * 一个0一个1,1再加上这个根,2就是这么得到的,
		 * 你怎么知道7的高度是1,因为他的左子树是0,右子树是0
		 * 两个最大的是0,再加上个根,等于1,递归
		 * 首先大家要有这个思想,因为树的定义本来就是递归的,
		 * 所以解决问题往递归来想,如果这个能够想清楚,代码估计就差不多了
		 * 
		 * 二叉树的高度是4,是4吧,怎么不是4,把7去了就变成3
		 * 我们把7去一下,那就变成3了,如果出来个3就差不多了
		 * 
		 */
		System.out.println(btree.getHeight());
		
		/**
		 * 二叉树的节点数量
		 * 把我们要实现二叉树的框架,都给大家搭建出来了
		 * 
		 * 返回二叉树的节点数量,他用了多少个节点
		 * 节点数量输出一下,这里面我们有一个方法,
		 * 我完全可以这么来写
		 * 
		 * 二叉树的节点数是7个
		 */
		System.out.println(btree.size());
		
		
	}
	
}

猜你喜欢

转载自blog.csdn.net/Leon_Jinhai_Sun/article/details/89671727