不关注理论,直接理解程序
假设我们要将节点值按顺序存入list。
不管哪个顺序,
都会用到一个stack
都可以用相似结构的算法完成
都只用到了一条 将节点值加入list的 核心语句
先序
算法总框架为一个while循环,判断条件为
while(root!=null||stack!=empty){
}
因为判断条件有两个,所以我们在循环中要完成两件事。
第一件事:往栈中存节点,直到节点为空
while (root!=null) {
list.add(root.value); //体现顺序的核心语句
stack.push(root);
root=root.left;
}
第二件事:使用栈中数据
root=stack.pop();
root=root.right;
完整算法
while(root!=null||stack!=empty){
while (root!=null) {
list.add(root.value); //体现顺序的核心语句
stack.push(root);
root=root.left;
}
root=stack.pop();
root=root.right;
}
中序 和前序很像,仅一句之差
算法总框架为一个while循环,判断条件为
while(root!=null||stack!=empty){
}
因为判断条件有两个,所以我们在循环中要完成两件事。
第一件事:往栈中存节点,直到节点为空
while (root!=null) {
stack.push(root); //体现顺序的核心语句换了位置
root=root.left;
}
第二件事:使用栈中数据
root=stack.pop();
list.add(root.value); //体现顺序的核心语句到了这里
root=root.right;
完整算法
while(root!=null||stack!=empty){
while (root!=null) {
stack.push(root);
root=root.left;
}
root=stack.pop();
list.add(root.value); //体现前序的核心语句
root=root.right;
}
后序 复杂原因:在使用栈中数据时仍不能将节点值加入list
后序算法额外维持一个节点变量prev,表示刚刚遍历过的那个节点
TreeNode prev = null;
算法总框架为一个while循环,判断条件为
while(root!=null||stack!=empty){
}
因为判断条件有两个,所以我们在循环中要完成两件事。
第一件事:往栈中存节点,直到节点为空
while (root!=null) {
stack.push(root); //体现顺序的核心语句不在这里
root=root.left;
}
第二件事:使用栈中数据,直到栈为空
root=stack.pop(); //体现顺序的核心语句也不在这里
if (root.right==null||root.right==prev) { //第一个条件表示没有右节点了,那肯可以去遍历根节点,第二个条件表示右节点遍历结束了,那肯定也可以去遍历根节点。
list.add(root.value); //体现顺序的核心语句在这里
prev=root; //将刚遍历过的节点赋给prev
root=null; //为了不重新进入第一件事的循环
} else { //否则表示还没到遍历根节点的时间
stk.emplace(root); //将根节点重新入栈
root=root.right; //去搞右节点
}
完整算法
TreeNode prev = null;
while(root!=null||stack!=empty){
while (root!=null) {
stack.push(root); //体现顺序的核心语句不在这里
root=root.left;
}
root=stack.pop(); //体现顺序的核心语句也不在这里
if (root.right==null||root.right==prev) { //第一个条件表示没有右节点了,那肯可以去遍历根节点,第二个条件表示右节点遍历结束了,那肯定也可以去遍历根节点。
list.add(root.value); //体现顺序的核心语句在这里
prev=root; //将刚遍历过的节点赋给prev
root=null; //为了不重新进入第一件事的循环
} else { //否则表示还没到遍历根节点的时间
stk.emplace(root); //将根节点重新入栈
root=root.right; //去搞右节点
}
}