分类
如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PVDQWBSB-1667919759460)(代码随想录刷题.assets/image-20221108155237929.png)]
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HWf3QNFU-1667919759462)(代码随想录刷题.assets/image-20221108155342075.png)]
二叉搜索树
有数值的数,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GMqAAKPk-1667919759462)(代码随想录刷题.assets/image-20221108155615428.png)]
平衡二叉搜索树
在二叉搜索树的基础上,左右的高度差不超过1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iqYyMGr6-1667919759463)(代码随想录刷题.assets/image-20221108160216603.png)]
二叉树存储方式
链式和顺序存储
链式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7GleA4af-1667919759463)(代码随想录刷题.assets/image-20221108160340974.png)]
顺序
在数组中的存储规则:
父节点的下标为i,左孩子就是i*2+1,右孩子就是i*2+2。
二叉树的定义
递归三部曲:
1.确定递归的终止条件
2.确定函数的参数和返回值
3.单层递归的逻辑
前序的顺序是中左右
下图模拟递归的执行流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5uZpxH4V-1667919759464)(代码随想录刷题.assets/image-20221108171054339.png)]
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
//递归三部曲
//1.确定递归终止条件
//2.确定递归的返回值
//3.单层内的递归逻辑
List<Integer> res=new ArrayList<>();
if(root==null) return res;
helper(root,res);
return res;
}
public void helper(TreeNode node,List<Integer> res){
if(node==null) return;
res.add(node.val);
if(node.left!=null) helper(node.left,res);
if(node.right!=null) helper(node.right,res);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ychmsXWq-1667919759464)(代码随想录刷题.assets/image-20221108172502212.png)]
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null) return res;
helper(root,res);
return res;
}
public void helper(TreeNode node,List<Integer> res){
if(node==null) return;
if(node.left!=null) helper(node.left,res);
if(node.right!=null) helper(node.right,res);
res.add(node.val);
}
}
遍历示意图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Qb7BbkZ-1667919759465)(代码随想录刷题.assets/image-20221108172310462.png)]
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null) return res;
helper(root,res);
return res;
}
public void helper(TreeNode node,List<Integer> res){
if(node==null) return;
if(node.left!=null) helper(node.left,res);
res.add(node.val);
if(node.right!=null) helper(node.right,res);
}
}
用一个栈来实现,前序遍历 入栈的顺序是先右节点,再左节点,这样子出栈的顺序才变成先左节点,再右节点。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2hrNRDSn-1667919759465)(代码随想录刷题.assets/image-20221108212424838.png)]
public List<Integer> preorderTraversal(TreeNode root) {
//通过栈的形式来实现
List<Integer> res=new ArrayList<>();
if(root==null) return res;
Stack<TreeNode> stack=new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node=stack.peek();//第一个节点弹出
stack.pop();
res.add(node.val);
if(node.right!=null) stack.push(node.right);
if(node.left!=null) stack.push(node.left);
}
return res;
}
根据前序遍历而来
前序遍历:中左右 把左右节点顺序交换 再反转数组,得到后续遍历
中左右------》 中右左------------》 左右中
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null) return res;
Stack<TreeNode> stack =new Stack<>();
stack.push(root);
while(!stack.empty()){
TreeNode node=stack.peek();
stack.pop();
res.add(node.val);
if(node.left!=null) stack.push(node.left);
if(node.right!=null) stack.push(node.right);
}
// System.out.println(res);
Collections.reverse(res);
return res;
}
思想:
由于访问节点的顺序和处理节点的顺序不一样
用一个指针记录当前所遍历的位置
while内的逻辑
1.当左边节点不为空的时候,就把左边的节点加入到栈中
2.当左边节点为空了 cur记录当前栈顶元素,栈顶元素出栈,加入res
3.令cur=右边节点
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null) return res;
//一直往左遍历到底
Stack<TreeNode> stack =new Stack<>();
//用一个指针记录遍历的位置
TreeNode cur=root;
while(cur!=null || !stack.empty()){
if(cur!=null){
//左边不为空
stack.push(cur);
cur=cur.left;
}else{
//左边为空
cur=stack.peek();
stack.pop();
res.add(cur.val);
cur=cur.right;
}
}
return res;
}
用一个空节点记录下一个节点是要被处理的元素
class Solution {
public List<Integer> preorderTraversal(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(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈)
if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈)
st.push(node); // 添加中节点
st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
} else { // 只有遇到空节点的时候,才将下一个节点放进结果集
st.pop(); // 将空节点弹出
node = st.peek(); // 重新取出栈中元素
st.pop();
result.add(node.val); // 加入到结果集
}
}
return result;
}
}
class Solution {
public List<Integer> inorderTraversal(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(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈)
st.push(node); // 添加中节点
st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈)
} else { // 只有遇到空节点的时候,才将下一个节点放进结果集
st.pop(); // 将空节点弹出
node = st.peek(); // 重新取出栈中元素
st.pop();
result.add(node.val); // 加入到结果集
}
}
return result;
}
}
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;
}
}