变量 | 方法 |
---|---|
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
}
有兔同学有疑惑了,你这个没用泛型好吗?当然不好,其实为了是一些集合有通用性,是要用到泛型的,我希望各位兔宝宝可以去探索一下,以后我会用泛型挨个实现地。
// 中序遍历
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,相当于回退操作,再把它打印出来。直到最后栈空了,遍历完成。
图解:这个是循环,看懂了就不必再看了,我在此处写完整。我花时间,你们别花时间了,建议至少看到第七步。
树的形状:
第一步:A结点不空入栈,引用(tempNode)指向左孩子B.
第二步:B不空,B入栈,引用指向B的左孩子(空)
第三步:引用为空执行else:第一句把栈顶的元素赋给引用,即引用(tempNode)为B。再把B打印出来。实际上引用退回了B,然后将引用指向引用的右孩子,B的右孩子即D.
第四步:D不为空,入栈,把引用指向D的左孩子(空)
第五步:引用空,执行else:D出栈,引用回退至D,再打印D。然后引用赋值D的右孩子(空)
第六步:引用空,执行else:A出栈,引用回退至A,打印A。然后引用赋值A右孩子C。
第七步:栈空,但引用不空,执行 if:C入栈,引用指向C的左孩子E.
第八步:E不空,入栈,引用指向E的左孩子(空)
第九步:引用空,E出栈,引用回退至E,打印E,最后引用指向E的右孩子F
第十步:F不空,F入栈,引用指向F的左孩子(空)
第十一步:引用空,F出栈,引用回退至F,打印F,引用指向F右孩子(空)
第十二步:引用空,C出栈,引用回退至C,打印C,引用指向C的右孩子(空)
第十三步:栈空,引用空。结束while,结束方法。打印出来的结果就是出栈的顺序:B D A E F C
先序和中序的区别就是将根节点和左孩子换一下位置,所以结构几乎一样,顺序不同
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
这个需要两个栈了一个用来实现遍历,一个用来实现输出。先看代码,我们画图详解
//后序遍历
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
由于中序和先序遍历我们都是遍历和输出同时进行,所以按逻辑来。后序遍历需要把输出储存到栈里面,所有入栈要根节点先入栈,右孩子入栈,左孩子入栈。输出栈里的元素是反向的,即为左右根顺序!
话不多说,老表上图,不再低调!
第一步:引用(tempNode)指向头结点A,不为空,执行第一个while,执行if:把根节点A赋值给输出栈(outputStack),在赋值一份给tempStack栈,然后引用指向A的右孩子C.
第二步:引用,栈都不空,继续执行第一个while,执行if:把节点C赋值给输出栈(outputStack),在赋值一份给tempStack栈,然后引用指向C的右孩子空.
第三步:引用空,tempStack不空,继续执行第一个while,此时由于tempNode引用空的,执行else语句:tempStack出栈,并把栈顶元素C交给引用,然后引用指向C的左孩子E.
第四步:引用空,继续执行第一个While,执行if:E入output栈,E入tempStack栈,引用指向E的右孩子F.
第五步:引用不空,执行if:F入output栈,F入tempStack栈,引用指向F的右孩子空。
第六步:引用空但是tempStack栈不空,继续while,执行else语句:tempStack出栈F,引用回退至F,引用指向F的左孩子(空)。
第七步:条件和第六步相同,tempStack出栈E,引用指向F,引用再指向E的左孩子(空)
第八步:依旧是重复六,执行else:tempStack中的A出栈,引用最后指向A的左孩子B。
第九步:tempStack空了,但是tempNode引用不为空,执行if:B入output栈,B入tempStack,引用指向B的右孩子D.
第九步:引用不空执行if:D入两个栈,然后引用指向D的右孩子(空)
第十步:引用空,tempStack栈不空,执行else:tempStack出栈D,引用指向D后,再指向他的左孩子(null)。
第十一步:栈不空,引用空,继续执行else:B出栈,引用指向B,然后指向B的左孩子(空)。
第十二步:栈空了,引用空了。结束第一个while。
脑子晕吗?多看看找规律,这就是重复重复再重复,我写都没有说难受呢,加把劲儿要完啦!
第十三步:执行第二个while,输出output栈里的东西。逆序输出哈:D B F E C A