目录
一、概念:
- 树是一种非线性的数据结构.
一棵二叉树是结点的一个有限集合,该集合:
1.
或者为空
2.
或者是由
一个根节
点加上两棵别称为
左子树
和
右子树
的二叉树组成。
二、性质
- 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1
- 具有n个结点的完全二叉树的深度k为
上取整
- 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i的结点有: 若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点 若2i+1<n,左孩子序号:2i+1,否则无左孩子;若2i+2<n,右孩子序号:2i+2,否则无右孩子;
三、遍历:
前序遍历 中序遍历 后序遍历 层序遍历
本质:就是在不同的时机,访问数据
前序遍历:根-左子树-右子树
中序遍历:左子树-根-右子树
后序遍历:左子树-右子树-根
四、程序
前序遍历
void preOrder(TreeNode root){
if(root==null){
return;
}
System.out.print(root.val+" ");
preOrder(root.left);
preOrder(root.right);
}
层序遍历:
public void leveOrder(Node root){
Queue<Node> queue =new LinkedList<>();
if (root!=null){
queue.offer(root);
}
while (!queue.isEmpty()){
Node cur=queue.poll();//出队列
System.out.print(cur.val+" ");
if (cur.left!=null){
queue.offer(cur.left);
if (cur.right!=null){
queue.offer(cur.right);
}
}
}
}
比较两棵树是否相同
- 检查根节点:结构、值
- 递归左树和右树
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p!=null&&q==null||p==null&&q!=null){
return false;
}
if(p==null&&q==null){
return true;
}
if(p.val!=q.val){
return false;
}
return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
}
}
判断另一颗树的子树
- 判断subRoot是不是和root相同
- 判断subRoot是不是和root左子树
- 判断subRoot是不是和root右子树
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root==null||subRoot==null){
return false;
}
if(isSameTree(root,subRoot)){//1
return true;
}if(isSubtree(root.right,subRoot)){//2
return true;
}
if(isSubtree(root.left,subRoot)){//3
return true;
}
return false;
}
判断是否平衡二叉树
平衡:每颗子树左右高度差不超过1
- root平衡
- root.left平衡
- root.right平衡
class Solution {
public int maxDepth(TreeNode root) {
if(root==null){
return 0;
}
int leftH=maxDepth(root.left);
int rightH=maxDepth(root.right);
return leftH>rightH?leftH+1:rightH+1;
}
public boolean isBalanced(TreeNode root) {
if(root==null){
return true;
}
int leftR=maxDepth(root.left);
int rightR=maxDepth(root.right);
return Math.abs(leftR-rightR)<=1&&isBalanced(root.left)&&isBalanced(root.right);
}
}
判断是否对称二叉树
- 一个为空,一个不为空
- 两个皆空
- 判断值是否相同
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null){
return false;
}
return isSomechild(root.left,root.right);
}
public boolean isSomechild(TreeNode leftTree,TreeNode rightTree){
if(leftTree==null&&rightTree!=null||leftTree!=null&&rightTree==null){
return false;
}
if(leftTree==null&&rightTree==null){
return true;
}
if(leftTree.val!=rightTree.val){
return false;
}
return isSomechild(leftTree.left,rightTree.right)&&isSomechild(leftTree.right,rightTree.left);
}
}
找二叉树中两个结点的公共祖先
- 左树,右树中查找都不为空,root为公共祖先
- 左树查找为空,右树查找不为空,证明两个节点都在右树,公共祖先为右树第一个
- 右树查找为空,左树查找不为空,证明两个节点都在左树,公共祖先为左树第一个
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}
if(root==p||root==q){
return root;
}
TreeNode leftTree=lowestCommonAncestor( root.left, p, q);//在左树中查找p、q
TreeNode rightTree=lowestCommonAncestor( root.right, p, q);//在右树中查找p、q
if(leftTree!=null&&rightTree!=null){
return root;
}
if(leftTree!=null&&rightTree==null){
return leftTree;
}
if(leftTree==null&&rightTree!=null){
return rightTree;
}
return null;
}
}
二叉树创建字符串
public String tree2str(TreeNode root) {
StringBuilder sb=new StringBuilder();
if(root==null){
return null;
}
tree2strchild(root,sb);
return new String(sb);
}
public void tree2strchild(TreeNode t,StringBuilder sb){
if(t==null){
return;
}
sb.append(t.val);
if(t.left!=null){
sb.append("(");
tree2strchild(t.left,sb);
sb.append(")");
}else{
if(t.right==null){
return;
}
else{
sb.append("()");
}
}
if(t.right==null){
return;
}else{
sb.append("(");
tree2strchild(t.right,sb);
sb.append(")");
}
}
二叉搜索树转换为一个排序的双向链表
- 二叉搜索树:左边都比跟小,右边都比根大。
- 排序:中序遍历这个二叉树
- 修改前驱、后继的指向
public TreeNode prev=null;
public void Convertchild(TreeNode pcur){
if(pcur==null){
return;
}
Convertchild(pcur.left);//中序遍历拿到一个节点,开始修改当前节点的指向
pcur.left=prev;
if(prev!=null){
prev.right=pcur;
}
prev=pcur;
Convertchild(pcur.right);
}
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null){
return null;
}
Convertchild(pRootOfTree);
TreeNode head=pRootOfTree;
while(head.left!=null){
head=head.left;
}
return head;
}