目录
5.二叉树的创建及遍历: 给定一个带空格的前序二叉树序列 ,求它的 输出中序、后序遍历序列
6.二叉树的层序遍历:给二叉树的根节点 root ,返回其节点值的 层序遍历
8.二叉搜索树与双向链表:输入一棵二叉搜索树,将该二叉搜索树转换成一个 排序的 双向链表
9.从前序与中序遍历序列构造二叉树: preorder 和 inorder ,构造二叉树并返回其根节点。
10. 从中序与后序遍历序列构造二叉树: inorder 和 postorder,构造并返回二叉树
11. 根据二叉树创建字符串:二叉树的根节点root,采用前序遍历 的方式:
1.判断两个二叉树是否相同:节点数值相同,结构都相同
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;
}
//两个数的val相同
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
2.判断其中一棵树是否为另一棵树的子树
//另一棵树的子树:给定两个二叉树,判断其中一个数subroot是否是另一棵树root的子树
//首先判断两棵树是否都存在是否都为空,若两棵树相同也属于子树
//判断对应的左右子树是否是相同的
// 时间复杂度:O(m*n)
public boolean isSubTree(TreeNode root, TreeNode subroot) {
//只要有一个数为空就不符合子树条件
if (root == null || subroot == null) return false;
if (isSameTree(root, subroot)) {
return true; //判断两棵树是否相同
}
if (isSubTree(root.left, subroot)) {
return true; //判断subroot是否是左子树
}
if (isSubTree(root.right, subroot)) {
return true; //判断subroot是否是右边子树
}
return false;
}
3.判断是否是平衡二叉树
//给定一个二叉树,判断它是否是高度平衡的二叉树。-->/平衡二叉树的子树也是平衡二叉树
//解析:1.root左树高度-右树高度《=1;
//2.root的左树是平衡点,右树也是平衡点
public int height(TreeNode root) {
if (root == null) return 0;
int leftheight = height(root.left);
int rightheight = height(root.right);
if (leftheight >= 0 && rightheight >= 0 &&Math.abs(leftheight - rightheight) <= 1) {
return Math.max(leftheight,rightheight) +1;
}else {
return -1;
}
}
//时间复杂度O(N)
public boolean isBalanced(TreeNode root) {
if (root == null) return true;
return height(root) >= 0;
}
4.判断二叉树是否是平衡二叉树
//给你一个二叉树的根节点 root , 检查它是否轴对称--->
//解析:1.查看左树和右树是否对称:左树的左子树和右边树的右子树相同
//2.
public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {
if (leftTree != null && rightTree ==null) return false;
if (leftTree == null && rightTree !=null) return false;
if (leftTree == null && rightTree ==null) return true;
if (leftTree.val != rightTree.val) return false;
return isSymmetricChild(leftTree.left,rightTree.right) &&
isSymmetricChild(leftTree.right,rightTree.left);
}
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return isSymmetricChild(root.left,root.right);
}
5.二叉树的创建及遍历: 给定一个带空格的前序二叉树序列 ,求它的 输出中序、后序遍历序列
// 二叉树的创建及遍历 给定一个带空格的前序二叉树序列 ,求它的 输出中序、后序遍历序列 --->
//解析:1.前序遍历可以确定根节点,
public static void inorder(TreeNode root) {
if (root == null) return;
inorder(root.left);
System.out.print(root.val+" ");
inorder(root.right);
}
public static int i = 0;
public static TreeNode createTree(String str) {
TreeNode root = null;
if (str.charAt(i) != '#') {
root = new TreeNode(str.charAt(i)); //当前不是#即为根节点
i++;
root.left = createTree(str);
root.right = createTree(str);
}else {
i++; //遇到#只需i++
}
return root;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String str = scanner.nextLine();
TreeNode root = createTree(str);
inorder(root);
}
}
6.二叉树的层序遍历:给二叉树的根节点 root ,返回其节点值的 层序遍历
// (即逐层地,从左到右访问所有节点)。-----》用队列完成
//解析:
public void levelOder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
if (root == null) return ;
queue.offer(root); //根放入队列
while (!queue.isEmpty()) {
TreeNode cur = queue.poll();
System.out.print(cur.val+" ");
if (cur.left != null) {
queue.offer(cur.left);
}
if (cur.right != null) {
queue.offer(cur.right);
}
}
}
//============层序遍历=============================================================//
// public List<List<Integer>> levelOrder(TreeNode root) {
// List<List<Integer>> ret = new ArrayList<>();
// if (root == null) return ret;
//
// Queue<TreeNode> queue1 = new LinkedList<>();
// queue1.offer(root); //根放入队列
//
// while (!queue1.isEmpty()) {
// int size = queue1.size(); // size代表当前层有多少个节点
// List<Integer> list = new ArrayList<>();
// while (size != 0) {
// TreeNode cur = queue1.poll();
// list.add(cur.val);
// if (cur.left != null) {
// queue1.offer(cur.left);
// }
// if (cur.right != null) {
// queue1.offer(cur.right);
// }
// size--;
// }
// ret.add(list);
// }
// return ret;
// }
7.二叉树p,q节点的 最近 公共 祖先LCA
/*孩子双亲表示法:---》链表求交点(用栈保存路径)
1.用两个栈的存储p,q路径(如何找到根节点到指定节点路径???--》遍历:)
2.求栈的大小
3.让栈中多的元素出差值个元素
4.开始出栈,直到栈顶元素相同,即此时是LCA最近公共祖先
*
* */
//获取路径root--》node:
//root根节点 node指定节点,stack存储指定节点路径
public boolean getPath(TreeNode root,TreeNode node,Stack<TreeNode> stack) {
if (root == null || node == null) return false; //若为空节点,则无路径
stack.push(root);
if (root == node) return true; //若根节点为node,找到了指定节点
//如果不是根节点,则需要在左右树寻找
boolean flg = getPath(root.left,node,stack); //左树寻找节点
if (flg == true) {
return true;
}
flg = getPath(root.right,node,stack);//右边树寻找节点
if (flg == true) {
return true;
}
stack.pop(); //左右树都没找到指定节点node,则需要弹出pop()
return false;
}
public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
if(root == null) return null;
Stack<TreeNode> stack1 = new Stack<>();
getPath(root,p,stack1);//存储root到p的路径到stack1
Stack<TreeNode> stack2 = new Stack<>();
getPath(root,q,stack2);//存储root到q的路径到stack2
int size1 = stack1.size(); //得到两个栈的大小
int size2 = stack2.size();
if (size1 > size2) { //取两个栈差值个元素
int size = size1-size2;
while (size != 0) {
stack1.pop(); //size大的栈stack1开始出元素,直至两个栈元素相同
size--;
}
while (!stack1.isEmpty() && !stack2.isEmpty()) {//两个栈都不为空
if (stack1.peek() == stack2.peek()) { //两个栈顶元素相同,则找到公共祖先
return stack1.pop();
}else {
stack1.pop();
stack2.pop();
}
}
}else {
int size = size2-size1;
while (size != 0) {
stack2.pop(); //size大的栈stack2开始出元素,直至两个栈元素相同
size--;
}
while (!stack1.isEmpty() && !stack2.isEmpty()) {
if (stack1.peek() == stack2.peek()) {
return stack1.pop();
}else {
stack1.pop();
stack2.pop();
}
}
}
return null;
}
8.二叉搜索树与双向链表:输入一棵二叉搜索树,将该二叉搜索树转换成一个 排序的 双向链表
* 解析:1.二叉搜素树:左树<根<右树---> 中序遍历 即有序
* 2.双向链表:left做前驱prev,right后继next
* 3.操作:中序遍历过程中:修改每个节点的left,right
*
* */
TreeNode prev = null;
public void inorder1(TreeNode pCur) {
if (pCur == null) return;
inorder1(pCur.left); //左
pCur.left = prev;
if (prev != null) {
prev.right = pCur;
}
prev = pCur;
// System.out.print(pCur+" ");//根
inorder1(pCur.right); //右
}
public TreeNode convert(TreeNode pRootOfTree) {
if (pRootOfTree == null) return null;
inorder1(pRootOfTree);
TreeNode head = pRootOfTree;
while (head.left != null) {
head = head.left;
}
return head;
}
9.从前序与中序遍历序列构造二叉树: preorder 和 inorder ,构造二叉树并返回其根节点。
/*105. 从前序与中序遍历序列构造二叉树: 两个整数数组 preorder 和 inorder ,构造二叉树并返回其根节点。
preorder 是二叉树的先序遍历(可得根节点),inorder是其中序遍历(确定左右树元素),
*解析:1.先将Pi下标元素,创建为root
2.中序遍历数组中找到当前下标Pi元素
3.root.left=?
4.root.right=?
* */
//通过前序中序遍历创建树:前序遍历数组preorder,索引下标preindex; 中序遍历数组inorder,下标(左inbegin 右inend)
public int preIndex = 0;
public TreeNode1 createNewTree(int[] preorder,int[] inorder,int inbegin,int inend) {
//满足此条件 则 说明 没有左树或者右树
if (inbegin > inend) return null;
//此处TreeNode为char类型,但是应该是int类型,需要在前面定义class TreeNode { public int val;}
TreeNode1 root = new TreeNode1(preorder[preIndex]);
//寻找前序遍历preIndex下标出的元素(preorder[preIndex]) 在中序遍历 里对应的位置
int rootindex = findIndexOfInorder(inorder,inbegin,inend,preorder[preIndex]);
if (rootindex == -1) return null;
preIndex++;
root.left = createNewTree(preorder,inorder,inbegin,rootindex-1); //左右树递归
root.right = createNewTree(preorder,inorder,rootindex+1,inend);
return root;
}
//寻找其对应在中序遍历的位置::中序遍历--起始索引值--数值key
private int findIndexOfInorder(int[] inorder,int inbegin,int inend,int key) {
for (int i = inbegin; i <= inend; i++) {
if (inorder[i] == key) {
return i;
}
}
return -1;
}
public TreeNode1 buildTree(int[] preorder,int[] inorder) {
if (preorder == null || inorder == null) return null;
return createNewTree(preorder,inorder,0,inorder.length-1);
}
10. 从中序与后序遍历序列构造二叉树: inorder 和 postorder,构造并返回二叉树
/* * 106. 从中序与后序遍历序列构造二叉树:给定两个整数数组 inorder 和 postorder
inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,构造并返回二叉树
*解析:1.先将Pi下标元素,创建为root
2.中序遍历数组中找到当前下标Pi元素
3.root.right=?
4.root.left=?
*/
//通过前序中序遍历创建树:前序遍历数组preorder,索引下标preindex; 中序遍历数组inorder,下标(左inbegin 右inend)
public int postIndex = 0;
public TreeNode1 createNewTree1(int[]inorder, int[] postorder, int inbegin,int inend) {
//满足此条件 则 说明 没有左树或者右树
if (inbegin > inend) return null;
//此处TreeNode为char类型,但是应该是int类型,需要在前面定义class TreeNode { public int val;}
TreeNode1 root = new TreeNode1(postorder[postIndex]);
//寻找前序遍历preIndex下标出的元素(preorder[preIndex]) 在中序遍历 里对应的位置
int rootindex = findIndexOfInorder1(inorder,inbegin,inend,postorder[postIndex]);
if (rootindex == -1) return null;
postIndex--;
//分别创建右子树,和左子树
//左右子树下标分别为:左边:inbegin,rootindex-1; 右边:rootindex+1,inend
root.right = createNewTree1(inorder,postorder,rootindex+1,inend); //左右树递归
root.left = createNewTree1(inorder,postorder,inbegin,rootindex-1);
return root;
}
//寻找其对应在中序遍历的位置::中序遍历--起始索引值--数值key
private int findIndexOfInorder1(int[] inorder,int inbegin,int inend,int key) {
for (int i = inbegin; i <= inend; i++) {
if (inorder[i] == key) {
return i;
}
}
return -1;
}
public TreeNode1 buildTree1(int[] inorder,int[] postorder) {
if (postorder == null || inorder == null) return null;
postIndex = postorder.length-1;
return createNewTree1(inorder,postorder,0,inorder.length-1);
}
11. 根据二叉树创建字符串:二叉树的根节点root,采用前序遍历 的方式:
/*根据二叉树创建字符串:二叉树的根节点root,,采用前序遍历 的方式:
将二叉树转化为: 一个由 括号和整数 组成的字符串,返回构造出的字符串。(空格以括号的形式输出)
*
*/
public void treeToString(TreeNode t,StringBuilder sb) {
if (t == null) return;
sb.append(t.val); //根不为空,进行拼接append
if (t.left != null) { //t的左边不为空,拼接左括号“(”
sb.append("(");
treeToString(t.left,sb); //继续递归操作,查找每一个左树
sb.append(")");//左树走完,拼接append右括号“)”
}else { //左树为空的情况下,考虑左子树的右树
if (t.right ==null) {
return;
}else {
sb.append("()");
}
}
//考虑右树的情况
if(t.right ==null) return;
sb.append("(");
treeToString(t.right,sb);//执行右树递归操作
sb.append(")");//右树树走完,拼接append右括号“)”
}
public String tree2str(TreeNode root) {
if (root == null) return null;
StringBuilder sb = new StringBuilder(); //StringBuilder用拼接操作,不会产生太多临时变量
treeToString(root,sb);
return sb.toString();
}