0 相关概念
二叉树的特点:
- 每个节点最多有两个子树
- 每个子节点都是父节点的左子节点或者右子节点
满二叉树的特点:
- 叶子节点都在最下一层
- 节点总数为(2^n-1)个(n为树的深度;减一是因为根节点只有一个)
完全二叉树的特点:
- 所有叶子结点都在最后一层或者倒数第二层
- 最后一层的叶子节点在左边连续,倒数第二层的节点在右边连续
- 满二叉树一定是一个完全二叉树
- 已知完全二叉树的总节点个数为n求叶子节点个数:当n为奇数时:(n+1)/2;当n为偶数时 : n/2
- 已知完全二叉树的总节点个数为n求父节点个数:当n为奇数时:(n-1)/2;当n为偶数时:n/2
- 已知完全二叉树的总结点数为n,求叶子节点数为2的父节点个数:当n为奇数时:(n-1)/2
当n为偶数时 : n/2-1
class Solution {
public int countNodes(TreeNode root) {
if(root==null) return 0;
int left = countlevel(root.left);
int right = countlevel(root.right);
if(left==right) {
return countNodes(root.right)+(1<<left);
}
else{
return countNodes(root.left)+(1<<right);
}
}
public int countlevel(TreeNode root){
int level=0;
while(root!=null){
level++;
root=root.left;
}
return level;
}
}
引自:https://blog.youkuaiyun.com/m0_37605197/article/details/107865906
树的前中后序遍历方法(略)。
1.顺序存储二叉树
数组存储方式和树的存储方式可以互相转换,一个数组可以转换为顺序存储二叉树。
顺序存储二叉树的特点 :
- 顺序二叉树通常只考虑完全二叉树
- 第n个元素的左子节点在数组中的索引为2*n+1
- 第n个元素的右子节点在数组中的索引为2*n+2
- 第n个元素的父节点在数组中的索引为(n-1)/2
- 树的第一个非叶子节点在数组中的索引为(arr.length/2)-1
2.线索化二叉树
线索化二叉树的特点:
- n个节点的二叉链表中含有n+1(2n-(n-1)=n+1)个空指针域。利用二叉链表中的空指针域,存放指向节点在某种遍历次序下的前驱和后继节点的指针(这种附加的指针称为“线索”)。
- 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
- 一个节点的前一个节点,称为前驱节点
- 一个节点的后一个节点,称为后继节点
遍历线索化二叉树:
遍历线索化二叉树不能使用树的遍历方式,可以使用线性的方式遍历,提高了遍历的效率。遍历的次序应当和构建线索化的次序保持一致。
3.二叉排序树
二叉排序树添加节点的方法
public void add(Node node,Node curnode) {
if(root==null) {
root=node;
return;
}
if(node.value<curnode.value) {
if(curnode.left!=null) {
add(node,curnode.left);
}else {
curnode.left=node;
}
}else {
if(curnode.right!=null) {
add(node,curnode.right);
}else {
curnode.right=node;
}
}
————————————————
版权声明:本文为优快云博主「lzy970613」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/lzy970613/article/details/106784199
二叉排序树删除节点的方法:
//删除节点
/**
* 分三种情况,删除的是叶子节点,直接通过父节点删除
* @param val
*/
public void delNode(int val) {
Node cur=search(val);
Node par=searchParent(val);
if(cur==null) {
System.out.println("没有该节点");
return;
}
//删除的只有一个根节点,父节点为null
if(cur==root&&cur.left==null&&cur.right==null) {
root=null;
return;
}
//删除的根节点只有一个子节点
if(cur==root) {
if(root.left!=null) {
root=root.left;
}else {
root=root.right;
}
return;
}
//要删除的是是叶子节点
if(cur.left==null&&cur.right==null) {
if(par.left==cur) {
par.left=null;
}else {
par.right=null;
}
return;
}
//左子树找最大的节点代替删除的,右子树找最小的节点代替删除的,任选其一
//要删除的是有两颗子树的节点
if(cur.left!=null&&cur.right!=null) {
Node tar=cur.right;
//找右子树最小的节点
while(tar.left!=null) {
tar=tar.left;
}
delNode(tar.value);//删除那个叶子节点
cur.value=tar.value;
return;
}
//删除的是由一颗子树的节点
if(cur.left!=null&&par.left==cur) {
par.left=cur.left;
}
if(cur.left!=null&&par.right==cur) {
par.right=cur.left;
}
if(cur.right!=null&&par.left==cur) {
par.left=cur.right;
}
if(cur.right!=null&&par.right==cur) {
par.right=cur.right;
}
}
//查找要删除的节点,非递归的方式
public Node search(int val) {
Node cur=root;
while(true) {
if(cur==null) {
System.out.println("树种没有该节点");
return null;
}
if(cur.value==val) {
return cur;
}
if(cur.left!=null&&val<cur.value) {
cur=cur.left;
}else if(cur.right!=null&&val>cur.value) {
cur=cur.right;
}else {
return null;
}
}
}
//查找要删除的父节点
public Node searchParent(int val) {
Node cur=root;
if(val==root.value) {
System.out.println("要删除的是根节点,无父节点");
return null;
}
while(true) {
if(cur.left!=null&&cur.left.value==val) {
return cur;
}
if(cur.right!=null&&cur.right.value==val) {
return cur;
}
if(cur.left!=null&&val<cur.value) {
cur=cur.left;
}else if(cur.right!=null&&val>cur.value){
cur=cur.right;
}else {
return null;
}
}
}
————————————————
版权声明:本文为优快云博主「lzy970613」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/lzy970613/article/details/106784199
4.平衡二叉树(AVL树)
在向二叉排序树添加节点时,如果节点时有序的,则树容易变成一个斜树,没有了树的特点。
平衡二叉树的特点:
- 平衡二叉树是一颗二叉排序树
- 它是一颗空树或它的左右两个子树的高度差的绝对值不超过1
- 左右两个子树都是一颗平衡二叉树
平衡二叉树的经典实现有:红黑树、AVL、替罪羊树,Treap、伸展树等。
5.红黑树
红黑树是一颗平衡二叉树。
红黑树的5个特点:
- 每一个结点都有颜色标记,红色或者黑色的
- 根节点是黑色的
- 为null或nil的叶子节点是黑色的
- 红色节点的子节点只能是黑色的
- 从一个节点到该节点子孙节点的所有路径上包含相同数目的黑色节点
参考文章:https://blog.youkuaiyun.com/qq_41854763/article/details/82694873
红黑树的重要应用:java8的Hashmap中的链表转为了红黑树,MySQL中的Innodb,c中的数据结构set和map。