二叉树遍历
当前掌握了二叉树三种遍历方法:
1.递归遍历 2.非递归遍历(迭代遍历) 3.统一迭代法
遍历分为三种方式:
1.前序遍历:中→左→右
2.中序遍历:左→中→右
3.后序遍历:左→右→中
First,递归遍历
递归算法的三个要素(以本题为例):
1.确定递归函数的参数和返回值。
遍历节点的数值不需要返回值 所以定义为void
void order(TreeNode root,List<Integer> result)
2.确定终止条件。
当遍历到的节点为空时,本层递归结束
if(root==null) return;
3.确定单层递归的逻辑
以前序遍历为例 中→左→右 所以先取中节点的数值,再处理左子树和右子树
result.add(root.val);
order(root.left,result);
order(root.right,result);
完整代码如下(前序遍历):
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result =new ArrayList<Integer>();
preorder(root,result);
return result;
}
public void preorder(TreeNode root,List<Integer> result){
if(root==null){return;}
result.add(root.val);
preorder(root.left,result);
preorder(root.right,result);
}
}
Then,非递归遍历(迭代遍历)
这里要使用到栈结构Stack<TreeNode> stack =new Stack<>();
因为递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数。所以在进行非递归遍历时需要一个栈结构。
注意:不要忘记 if(root==null) return result;
我的思路(纯个人理解):
前序遍历(中→左→右):
- 先把根节点push进栈中
- 当stack不为空时,栈pop,值加入队列之中。(1.2.是先对根节点进行处理)
- 先push右节点再push左节点。(因为pop出来时就是先左后右)。然后弹出把值加入队列之中。
- 最后返回result队列。
中序遍历(左→中→右):
此时栈我理解为一个暂存空间。
- 先把从根节点开始的所有左子树节点放入栈中,当遇到第一个左节点为null的节点时(此时 node==null),此时该栈的栈顶就是最左边的节点,pop它,并且把它加入到result队列中。(左)
- 然后再往右遍历,把该节点的右子树节点入栈,若没有右子树节点,pop出它的上一节点。(中)
- 则此时pop出的是最左边节点的上一节点,然后再往右遍历,把右子树节点入栈,循环往复。(右)
完整代码如下(中序遍历):
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result =new ArrayList<>();
Stack<TreeNode> stack =new Stack<>();
if(root==null){return result;}
TreeNode node = root;
while(node!=null||!stack.isEmpty()){
if(node!=null){
stack.push(node);
node=node.left; //向左子树节点遍历
}else{
node =stack.pop(); //找到左子树节点
result.add(node.val);
node=node.right; //向右子树节点遍历
}
}
return result;
}
}
后序遍历(左→右→中):
后序遍历写法与前序遍历类似 但要进行改进
思路:前序遍历:中→左→右 先改为中→右→左 最后再进行反转 则是左→右→中
反转操作:Collections.reverse(result);
Finally,统一迭代法
方法:将要访问的节点放入栈,将要处理的节点也放入栈中但是要做标记(null)。-标记法
只需要改几行代码!!!
前序遍历代码顺序:
- 分别定义一个队列和一个栈
- root不为空时push入栈
- 栈不为空时,node是栈中peek一下栈顶元素
- 当node不为空时 先pop一下(将root先pop出去,避免重复操作)
- 然后添加右节点,左节点,中节点并null标记一下
- 当node为空时,先将空节点pop,再重新peek一下栈顶元素,再pop
- 最后把node的值加入队列
- 返回队列
中序遍历:
只改变步骤5
5 .添加右节点,中节点并null标记一下,左节点
后序遍历:
同上
5.添加中节点并null标记一下,右节点,左节点
完整代码如下(后序遍历):
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> st = new Stack<>();
if (root != null) st.push(root);
while (!st.empty()) {
TreeNode node = st.peek();
if (node != null) {
st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
st.push(node); // 添加中节点
st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈)
if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈)
} else { // 只有遇到空节点的时候,才将下一个节点放进结果集
st.pop(); // 将空节点弹出
node = st.peek(); // 重新取出栈中元素
st.pop();
result.add(node.val); // 加入到结果集
}
}
return result;
}
}
DML&DQL
DML:数据操纵语言
DQL:数据查询语言
DML中主要是对表中的数据进行添加、修改和删除等操作。
添加:insert into 表名(列名1,2,。。。)values(值1,2,。。。)
修改:update 表名 set 列名1=值1 (where 条件)
删除:delete from 表名 (where条件)
DQL的操作具体可分为以下几类:
注意:null值在mysql中的比较不能使用= !=。需要使用is is not。
具体操作可查表