目录
首先让我们来了解一下树形结构树
树
树是什么呢?
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因
为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
- 根结点:根节点没有前驱结点。
- 除根节点外,其余结点被分成是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继。
- 因此,树是递归定义的。
二叉树
那么在知道了树是什么的情况下,我们可以进一步了解树形结构其中的一种特殊结构——二叉树
二叉树又是什么呢?
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。
二叉树的特点:
- 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
- 二叉树的子树有左右之分,其子树的次序不能颠倒。
特殊的二叉树
-
满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
- 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。
二叉树的性质
-
若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) 个结点.
-
若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h- 1.
-
对任何一棵二叉树, 如果度为0其叶结点个数为 n0, 度为2的分支结点个数为 n2,则有n0=n2+1
-
若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=Log2(n+1). (ps:Log2(n+1)是log以2为
底,n+1为对数) -
对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对
于序号为i的结点有:1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点 2. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子 3. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子
二叉树的存储结构分为:
顺序存储和类似与链表的链式存储
遍历方式
前序遍历:也叫先根遍历,根--左子树--右子树
中序遍历:左子树--根--右子树
后序遍历:左子树--右子树--根
层序遍历:每一层从左往右
例题
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root==null)
return null;
TreeNode l=invertTree(root.left);
TreeNode r=invertTree(root.right);
root.left=r;
root.right=l;
return root;
}
}
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p==null&&q==null){
return true;
}else if(p==null||q==null){
return false;
} else if (p.val!=q.val) {
return false;
}else{
return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
}
}
}
class Solution {
public boolean isSymmetric(TreeNode root) {
return check(root,root);
}
public boolean check(TreeNode a,TreeNode b){
if(a==null&&b==null){
return true;
}else if(a==null||b==null){
return false;
}else{
return a.val==b.val&&check(a.left,b.right)&&check(a.right,b.left);
}
}
}
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (subRoot==null)
return true;
if(root==null)
return false;
return isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot)||isSametree(root,subRoot);
}
public boolean isSametree(TreeNode a,TreeNode b){
if(a==null&&b==null){
return true;
}else if(a==null||b==null){
return false;
} else if (a.val!=b.val) {
return false;
}else {
return isSametree(a.left,b.left)&&isSametree(a.right,b.right);
}
}
}
class Solution {
public boolean isBalanced(TreeNode root) {
if(root==null){
return true;
}else {
return Math.abs(height(root.left)-height(root.right))<=1&&isBalanced(root.left)&&isBalanced(root.right);
}
}
public int height(TreeNode a){
if(a==null)
return 0;
else {
return Math.max(height(a.left),height(a.right))+1;
}
}
}
6.二叉树遍历_牛客题霸_牛客网 (nowcoder.com)
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
class TreeNodek{
public char val;
public TreeNodek left;
public TreeNodek right;
public TreeNodek(char k){
this.val=k;
}
}
public class Main {
public static int i=0;
public static TreeNodek createTree(String str){
TreeNodek node=null;
if(str.charAt(i)!='#'){
node=new TreeNodek(str.charAt(i));
i++;
node.left=createTree(str);
node.right=createTree(str);
}else {
i++;
}
return node;
}
public static void zhongxu(TreeNodek k){
if(k==null){
return;
}else {
zhongxu(k.left);
System.out.print(k.val+" ");
zhongxu(k.right);
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextLine()) { // 注意 while 处理多个 case
String s=sc.nextLine();
TreeNodek k=createTree(s);
zhongxu(k);
}
}
}
7.144. 二叉树的前序遍历 - 力扣(LeetCode)
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList<>();
Stack<TreeNode> stack= new Stack<TreeNode>();
while(root!=null||!stack.isEmpty()){
while(root!=null){
list.add(root.val);
stack.add(root);
root=root.left;
}
root=stack.pop();
root=root.right;
}
return list;
}
}
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList<>();
Stack<TreeNode> stack= new Stack<TreeNode>();
while(root!=null||!stack.isEmpty()){
while(root!=null){
stack.add(root);
root=root.left;
}
root=stack.pop();
list.add(root.val);
root=root.right;
}
return list;
}
}
9.145. 二叉树的后序遍历 - 力扣(LeetCode)
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList<>();
Stack<TreeNode> stack= new Stack<TreeNode>();
TreeNode prev=null;
while(root!=null||!stack.isEmpty()){
while(root!=null){
stack.add(root);
root=root.left;
}
root=stack.pop();
if(root.right==null||root.right==prev){
list.add(root.val);
prev=root;
root=null;
}else{
stack.add(root);
root=root.right;
}
}
return list;
}
}
10.106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
class Solution {
public static TreeNode create(int[] inorder,int[] postorder,int a1,int a2,int b1,int b2){
if(a1>a2||b1>b2)
return null;
int t=a1;
while(inorder[t]!=postorder[b2]&&t<=a2){
t++;
}
int len=t-a1;
TreeNode root=new TreeNode(postorder[b2]);
root.left=create(inorder,postorder,a1,t-1,b1,b1+len-1);
root.right=create(inorder,postorder,t+1,a2,b1+len,b2-1);
return root;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(inorder==null||postorder==null||inorder.length!=postorder.length)
return null;
int len=postorder.length-1;
return create(inorder,postorder,0,len,0,len);
}
}
11.105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
class Solution {
public static TreeNode create(int[] inorder,int[] preorder,int a1,int a2,int b1,int b2){
if(a1>a2||b1>b2)
return null;
int t=a1;
while(inorder[t]!=preorder[b1]&&t<=a2){
t++;
}
int len=t-a1;
TreeNode root=new TreeNode(preorder[b1]);
root.left=create(inorder,preorder,a1,t-1,b1+1,b1+len);
root.right=create(inorder,preorder,t+1,a2,b1+len+1,b2);
return root;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(inorder==null||preorder==null||inorder.length!=preorder.length)
return null;
int len=preorder.length-1;
return create(inorder,preorder,0,len,0,len);
}
}
12.236. 二叉树的最近公共祖先 - 力扣(LeetCode)(LCA问题)
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null)
return null;
if(root==p||root==q)
return root;
TreeNode l=lowestCommonAncestor(root.left,p,q);
TreeNode r=lowestCommonAncestor(root.right,p,q);
if(l!=null&&r!=null){
return root;
} else if (l!=null) {
return l;
}else {
return r;
}
}
}
13.107. 二叉树的层序遍历 II - 力扣(LeetCode)
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> z=new ArrayList<List<Integer>>();
if(root==null)
return z;
Queue<TreeNode> queue=new LinkedList<TreeNode>();
queue.add(root);
while(!queue.isEmpty()){
List<Integer> tmp=new ArrayList<Integer>();
int size=queue.size();
for (int i = 0; i < size; i++) {
TreeNode k=queue.poll();
tmp.add(k.val);
TreeNode l=k.left;
TreeNode r=k.right;
if(l!=null){
queue.add(l);
}
if(r!=null){
queue.add(r);
}
}
z.add(tmp);
}
Collections.reverse(z);
return z;
}
}
14.102. 二叉树的层序遍历 - 力扣(LeetCode)
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> z=new ArrayList<List<Integer>>();
if(root==null)
return z;
Queue<TreeNode> queue=new LinkedList<TreeNode>();
queue.add(root);
while(!queue.isEmpty()){
List<Integer> tmp=new ArrayList<Integer>();
int size=queue.size();
for (int i = 0; i < size; i++) {
TreeNode k=queue.poll();
tmp.add(k.val);
TreeNode l=k.left;
TreeNode r=k.right;
if(l!=null){
queue.add(l);
}
if(r!=null){
queue.add(r);
}
}
z.add(tmp);
}
return z;
}
}
15.606. 根据二叉树创建字符串 - 力扣(LeetCode)
class Solution {
public String tree2str(TreeNode root) {
if(root==null){
return "";
}
if(root.left==null&&root.right==null){
return Integer.toString(root.val);
}
if(root.right==null){
return new StringBuffer().append(root.val).append("(").append(tree2str(root.left)).append(")").toString();
}
return new StringBuffer().append(root.val).append("(").append(tree2str(root.left)).append(")(").append(tree2str(root.right)).append(")").toString();
}
}
结语
到此为止,您已经基本掌握二叉树所有的知识内容了,感谢您能非常耐心地一直看到这里,希望您能够在您的编程生涯中勇往直前!