前言:
上一篇,讲了队,接下来我们了解一下,二叉树,二叉树在数据结构中,是比较重要的一类知识 ,后面许多知识点的底层结构都是二叉树。
目录
1.二叉树的概念
树是一种非线性的数据结构。它是由n(n>=0)个有限节点组成一个具有层次关系的集合。
把它叫做树是因为它看起来像一颗倒挂的树,也就是它是根朝上,叶朝下。
节点的度:一个节点含有子树的个数称为节点的度,例如A的度为2.
树的度:所有节点度的最大值。
叶子节点或者终端节点:度为零的节点,例如:E F G J H为叶子节点。
双亲节点或父节点:若一个节点有字节点,则称这个节点为其其节点的父节点。例如:A是B的父节点。
孩子节点或者子节点:一个节点含有子树的根节点称为该节点的子节点。例如:B
C是A的孩子节点。
根节点:一棵树中,没有双亲节点的节点。例如:A
树的高度或深度:树种节点的最大层次。例如,上图,树的高度是4。高度是从1 开始
兄弟节点:具有相同父节点的节点互称兄弟节点。例如B C
堂兄弟节点:双亲在同一层的节点。
节点的祖先:从根节点到该节点所经分支上的所有节点。
森林:有m棵互不相交的树组成的集合称为森林。
2.二叉树
2.1:概念
一个二叉树是节点的一个有限集合,该集合:
1.或者为空
2.或者是由一个根节点加上两棵分为称为左子树和右子树的二叉树组成。
注意:
1.二叉树的度不存在大于2的节点
2.二叉树的子树有左右之分,次序不能颠倒,故二叉树是有序树。
2.2:两种特殊的二叉树
1.满二叉树:每层的节点数都到达最大值,如果一棵二叉树的层数为k,且节点总数是2^k-1,
则他就是满二叉树。
2.完全二叉树:当且仅当其每一个节点都与深度为K,的满二叉树种编号从0到n-1的节点,称为完全二叉树,其中满二叉树是一种特殊的完全二叉树。
3:二叉树的性质
1.若规定根节点的层数为1,则一颗非空二叉树的第i层上最多有2^i-1个节点。
2.若规定只有根节点的二叉树的深度为1,则深度为k的二叉树的最大节点是2^k-1(k>=0)
3.对任何一棵二叉树,如果其叶子节点个数为n0,度为2的非叶节点为n2 n0=n2+1
4.具有n个节点的完全二叉树的深度k为log2(n+1)----以2为底的对数,向上取整。
5.对于具有n个节点的完全二叉树,如果按照从上到下从左到右的顺序对所有节点从零开始编号,则对于有序为i的节点有:
若i>0,父亲节点:(i-1)/2.
若2i+1<n; 左孩子序号2i+1
若2i+2<n; 右孩子序号2i+2
4:二叉树的存储
二叉树的存储结构分为:顺序存储和类似链表的链式存储。
二叉树的链式存储时通过一个一个节点引用起来的,可以有双亲表示法,孩子表示法
public class My_TreeNode {
static class TreeNode{//创建一个节点
public char val;//存储节点的值
public TreeNode left;//指向左孩子
public TreeNode right;//指向右孩子
public TreeNode(char val) {
this.val = val;
}
}
public static TreeNode root=null;
}
5:二叉树的递归遍历和非递归遍历
5.1前序遍历----根左右
//这是递归
public static void preOrder(TreeNode root){
if(root==null){
return;
}
System.out.print(root.val+" ");
preOrder(root.left);
preOrder(root.right);
}
//非递归
//利用栈,先进后出,先放根节点,并打印,之后再放右孩子,再放左孩子
public static void preOrder1(TreeNode root){
Stack<TreeNode> stack=new Stack<>();
if(root==null){
return;
}
stack.push(root);
while (!stack.empty()){
TreeNode cur=stack.pop();
if(cur.right!=null){
stack.push(cur.right);
}
if(cur.left!=null){
stack.push(cur.left);
}
System.out.print(cur.val+" ");
}
System.out.println();
}
}
5.2:中序遍历----左根右
//非递归
public static void inorder1(TreeNode root) {
Stack<TreeNode> s1 = new Stack<>();
TreeNode cur = null;
if (root != null) {
cur = root;
while (!s1.empty() || cur != null) {
while (cur != null) {
s1.push(cur);
cur = cur.left;
}
if (!s1.empty()) {
cur = s1.pop();
System.out.print(cur.val + " ");
cur = cur.right;
}
}
}
}
}
5.3:后续遍历----左右根
public static void lastOrder(TreeNode root){
//判断根节点
if(root==null){
return;
}
//后续遍历,是左 右 根
lastOrder(root.left);
lastOrder(root.right);
System.out.print(root.val+" ");
}
//非递归的
public static void lastOrder1(TreeNode root) {
Stack<TreeNode> s1 = new Stack<>();
TreeNode cur = root;
TreeNode prev = null;
if(cur!=null) {
while (!s1.empty() || cur != null) {
while (cur != null) {
s1.push(cur);
cur = cur.left;
}
TreeNode top = s1.peek();
if (top.right == null
|| top.right == prev) {
System.out.print(top.val+" ");
s1.pop();
prev = top;
} else {
cur = top.right;
}
}
}
}
}
5.4:层序遍历
//层序遍历
public void sequence(TreeNode root) {
if (root == null) {
return;
}
Queue<TreeNode> stack = new LinkedList<>();
stack.offer(root);
while (!stack.isEmpty()) {
TreeNode cur = stack.poll();
if (cur.left != null) {//左孩子不为空,入队
stack.offer(cur.left);
}
if (cur.right != null) {//右孩子不为空,入队
stack.offer(cur.right);
}
System.out.print(cur.val + " ");
}
}
}
6.二叉树的其他操作
6.1:获取二叉树的高度
public int findHeight(TreeNode root){
//判断root是不是空节点
if(root==null){
return 0;
}
//递归问题,左右孩子树的高度
int left=findHeight(root.left);
int right=findHeight(root.right);
//左右孩子谁高度比较高
return left>right?left+1:right+1;
}
6.2:获取第K层节点的个数
public int getLevelNodeCount(TreeNode root,int k){
//判断root是否为空,k是否合法
if(root==null||k<0){
return 0;
}
if(k==1){
return 1;
}
//子问题,左右孩子第k层有多少节点
int tmp=getLevelNodeCount(root.left,k-1)+
getLevelNodeCount(root.right,k-1);
return tmp;
}
}
6.3:获取叶子节点的个数
public int getLeafNode(TreeNode root){
if(root==null){
return 0;
}
if(root.left==null&&root.right==null){
return 1;
}
int tmp=getLeafNode(root.left)+getLeafNode(root.right);
return tmp;
}
}
注意:
如果只给一个遍历,不能创建一棵树。
如果只给前序和后序,不能创建一棵二叉树。
总结:
以上就是我总结的二叉树的知识点,若有不正确的地方,请铁铁们,留言纠正。若感觉不错,请一键三连。