用栈实现二叉树的遍历——前序,中序,后序

第一步:建立一个简单的栈

Stack主要部分
变量 方法
MAX_DEPTH,data[] , depth push(),pop(),isEmpty()
/**
 * 
 */
package datastructure.stack;

/**
 ****************************
 * TODO
 * 
 * @author Chen Fan
 * @version 1.0 time 2022年1月3日
 ****************************
 */
public class ObjectStack {

	// 栈高,总容量
	public static final int MAX_DEPTH = 10;

	// 添加数据后的高度
	int depth;

	// 数据用数组来装
	Object[] data;

	// 构造方法,简单初始化一下下
	public ObjectStack() {
		depth = 0;
		data = new Object[MAX_DEPTH];
	} // Of the constuctor

	public String toString() {
		String resulString = "";
		for (int i = 0; i < depth; i++) {
			resulString += data[i];
		} // Of for i

		return resulString;
	} // Of String

	// 入栈方法
	public boolean push(Object paraObject) {
		if (depth == MAX_DEPTH) {
			System.out.println("Stack full.");
			return false;
		} // Of if

		data[depth] = paraObject;
		depth++;
		return true;
	} // Of push

	// 出栈方法
	public Object pop() {
		if (depth == 0) {
			System.out.println("Nothing to pop.");
			return '\0';
		} // Of if
		Object resultObject = data[depth - 1];
		depth--;

		return resultObject;
	} // Of pop

	// 判断栈是否为空的方法
	public boolean isEmpty() {
		if (depth == 0) {
			return true;
		} // Of if

		return false;
	} // Of isEmpty

	public static void main(String args[]) {
		ObjectStack tempStack = new ObjectStack();

		for (char ch = 'a'; ch < 'm'; ch++) {
			tempStack.push(new Character(ch));
			System.out.println("The current stack is: " + tempStack);
		} // Of for i

		char tempChar;
		for (int i = 0; i < 12; i++) {
			tempChar = ((Character) tempStack.pop()).charValue();
			System.out.println("Poped: " + tempChar);
			System.out.println("The current stack is: " + tempStack);
		} // Of for i
	}// Of main
}

有兔同学有疑惑了,你这个没用泛型好吗?当然不好,其实为了是一些集合有通用性,是要用到泛型的,我希望各位兔宝宝可以去探索一下,以后我会用泛型挨个实现地。

第二步:

2.1借用栈来实现中序遍历

	// 中序遍历
	public void inOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				tempStack.push(tempNode);
				tempNode = tempNode.leftChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				System.out.print("" + tempNode.value + " ");
				tempNode = tempNode.rightChild;
			} // Of if
		} // Of while
	} // Of inOrderVisit

        2.1创建一个栈,一个树节点引用。

        2.2进行while循环,中序遍历顺序是:根左右,在循环中。if:结点不为空(有孩子或者叶子结点)就把此节点入栈,else:如果是空节点,把栈顶元素出栈给tempNode,相当于回退操作,再把它打印出来。直到最后栈空了,遍历完成。

图解:这个是循环,看懂了就不必再看了,我在此处写完整。我花时间,你们别花时间了,建议至少看到第七步。

树的形状:

用栈实现二叉树的遍历——前序,中序,后序_第1张图片

 第一步:A结点不空入栈,引用(tempNode)指向左孩子B.

用栈实现二叉树的遍历——前序,中序,后序_第2张图片

 第二步:B不空,B入栈,引用指向B的左孩子(空)

用栈实现二叉树的遍历——前序,中序,后序_第3张图片

 第三步:引用为空执行else:第一句把栈顶的元素赋给引用,即引用(tempNode)为B。再把B打印出来。实际上引用退回了B,然后将引用指向引用的右孩子,B的右孩子即D.

用栈实现二叉树的遍历——前序,中序,后序_第4张图片

第四步:D不为空,入栈,把引用指向D的左孩子(空)

用栈实现二叉树的遍历——前序,中序,后序_第5张图片

 第五步:引用空,执行else:D出栈,引用回退至D,再打印D。然后引用赋值D的右孩子(空)

用栈实现二叉树的遍历——前序,中序,后序_第6张图片

 第六步:引用空,执行else:A出栈,引用回退至A,打印A。然后引用赋值A右孩子C。

用栈实现二叉树的遍历——前序,中序,后序_第7张图片

第七步:栈空,但引用不空,执行 if:C入栈,引用指向C的左孩子E.

 第八步:E不空,入栈,引用指向E的左孩子(空)

用栈实现二叉树的遍历——前序,中序,后序_第8张图片

 第九步:引用空,E出栈,引用回退至E,打印E,最后引用指向E的右孩子F

用栈实现二叉树的遍历——前序,中序,后序_第9张图片

 第十步:F不空,F入栈,引用指向F的左孩子(空)

第十一步:引用空,F出栈,引用回退至F,打印F,引用指向F右孩子(空)

 用栈实现二叉树的遍历——前序,中序,后序_第10张图片

 第十二步:引用空,C出栈,引用回退至C,打印C,引用指向C的右孩子(空)

用栈实现二叉树的遍历——前序,中序,后序_第11张图片

 第十三步:栈空,引用空。结束while,结束方法。打印出来的结果就是出栈的顺序:B D A E F C

2.2实现先序遍历

        先序和中序的区别就是将根节点和左孩子换一下位置,所以结构几乎一样,顺序不同

	public void preOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				System.out.print("" + tempNode.value + " ");
				tempStack.push(tempNode);
				tempNode = tempNode.leftChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				tempNode = tempNode.rightChild;
			} // Of if
		} // Of while
	} // Of preOrderVisitWithStack

2.3后序遍历

这个需要两个栈了一个用来实现遍历,一个用来实现输出。先看代码,我们画图详解

	//后序遍历
	public void postOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		ObjectStack tempoutputStack = new ObjectStack();
		
		while(!tempStack.isEmpty()||tempNode!=null) {
			if (tempNode != null) {
				
			//把要输出的结点按后序要求储存起来
			tempoutputStack.push(new Character(tempNode.value));
			tempStack.push(tempNode);
			tempNode = tempNode.rightChild;
		}else {
			tempNode = (BinaryCharTree) tempStack.pop();
			tempNode = tempNode.leftChild;
		}// Of if
	}// Of while
		
		//输出栈
		while(!tempoutputStack.isEmpty()) {
			System.out.print(""+tempoutputStack.pop()+" ");
		} // Of while
	} // Of postOrderVisitWithStackk

由于中序和先序遍历我们都是遍历和输出同时进行,所以按逻辑来。后序遍历需要把输出储存到栈里面,所有入栈要根节点先入栈,右孩子入栈,左孩子入栈。输出栈里的元素是反向的,即为左右根顺序!

话不多说,老表上图,不再低调!

用栈实现二叉树的遍历——前序,中序,后序_第12张图片

第一步:引用(tempNode)指向头结点A,不为空,执行第一个while,执行if:把根节点A赋值给输出栈(outputStack),在赋值一份给tempStack栈,然后引用指向A的右孩子C.

用栈实现二叉树的遍历——前序,中序,后序_第13张图片

 第二步:引用,栈都不空,继续执行第一个while,执行if:把节点C赋值给输出栈(outputStack),在赋值一份给tempStack栈,然后引用指向C的右孩子空.

用栈实现二叉树的遍历——前序,中序,后序_第14张图片

 第三步:引用空,tempStack不空,继续执行第一个while,此时由于tempNode引用空的,执行else语句:tempStack出栈,并把栈顶元素C交给引用,然后引用指向C的左孩子E.

用栈实现二叉树的遍历——前序,中序,后序_第15张图片

 第四步:引用空,继续执行第一个While,执行if:E入output栈,E入tempStack栈,引用指向E的右孩子F.

用栈实现二叉树的遍历——前序,中序,后序_第16张图片

 第五步:引用不空,执行if:F入output栈,F入tempStack栈,引用指向F的右孩子空。

用栈实现二叉树的遍历——前序,中序,后序_第17张图片

 第六步:引用空但是tempStack栈不空,继续while,执行else语句:tempStack出栈F,引用回退至F,引用指向F的左孩子(空)。

用栈实现二叉树的遍历——前序,中序,后序_第18张图片

 第七步:条件和第六步相同,tempStack出栈E,引用指向F,引用再指向E的左孩子(空)

用栈实现二叉树的遍历——前序,中序,后序_第19张图片

 第八步:依旧是重复六,执行else:tempStack中的A出栈,引用最后指向A的左孩子B。

用栈实现二叉树的遍历——前序,中序,后序_第20张图片

 第九步:tempStack空了,但是tempNode引用不为空,执行if:B入output栈,B入tempStack,引用指向B的右孩子D.

用栈实现二叉树的遍历——前序,中序,后序_第21张图片

 第九步:引用不空执行if:D入两个栈,然后引用指向D的右孩子(空)

用栈实现二叉树的遍历——前序,中序,后序_第22张图片

 第十步:引用空,tempStack栈不空,执行else:tempStack出栈D,引用指向D后,再指向他的左孩子(null)。

用栈实现二叉树的遍历——前序,中序,后序_第23张图片

 第十一步:栈不空,引用空,继续执行else:B出栈,引用指向B,然后指向B的左孩子(空)。

用栈实现二叉树的遍历——前序,中序,后序_第24张图片

 第十二步:栈空了,引用空了。结束第一个while。

脑子晕吗?多看看找规律,这就是重复重复再重复,我写都没有说难受呢,加把劲儿要完啦!

第十三步:执行第二个while,输出output栈里的东西。逆序输出哈:D B F E C A

你可能感兴趣的:(二叉树,栈,java)