就是一个看起来像一颗树的逻辑内存结构。由很多个结点(节点)组成,但是二叉树规定每个结点最多有两个子结点(两个分叉)
- 根结点:理解为树的根,树的入口,我们必须从根结点,才能找到其它结点
- 父结点:当前结点的父结点,比如图中A是B,C的父结点,C是F,G的父结点
- 子结点:就是当前结点的子结点,比如C和B是A的子结点
- 叶子结点:没有子结点的结点,比如H,E,F,G
- 路径:从根结点找到特定结点的路径
- 结点权:结点的额外值,有些情况下我们需要对比结点的权值,以判断开销最小的带权路径。
- 层(深度):树的层数,根结点自己算一层,如果它有子结点,子结点算一层,以此类推
- 树的高度:共有多少层
- 子树:上图中,A是整个二叉树,B是A的左子树,因为B结点是D、H、E结点的根结点。
- 森林:有多颗树,就是森林。
- 度:表示当前结点是一个什么样的结点。度可以看作结点间的连线。0度,代表这个结点没有子结点,也就是叶子结点。1度,代表这个结点又左或右子树。2度,表示这个结点同时有左右两颗子树
1. 第i层最多有2i-1个结点
2. 二叉树层数为n时,此二叉树最多有2n-1个结点(因为根结点是1个,自己算一层)
3. 叶子结点数为a个,度为2的结点数为b个。则a = b+1,也就是说,叶子结点,永远比度为2的结点多一个
- 满二叉树:除了叶子结点外,其它结点的度都为2。也就是除了最后一层的叶子结点,其它结点都有2个子结点
- 结点个数为(2^n)-1(n为层数,2的n次方,减一)
- 因为满二叉树,每一层都填满了(连续),所以满二叉树中第 i 层的节点数为 2n-1 个
- 深度为 k 的满二叉树必有 2k-1 个节点 ,叶子数为 2k-1
- 满二叉树中不存在度为 1 的节点,每一个分支点中都两棵深度相同的子树,且叶子节点都在最底层
- 具有 n 个节点的满二叉树的深度为 log2(n+1)----(对数公式都回吧?ax = N,x = logaN)---- 可以算出深度
- 完全二叉树:二叉树所有叶子结点,都在倒数第一和倒数第二层。倒数第一层叶子结点左边连续(值不用连续,就是不能缺一块,比如下图14没有左节点81,那么就缺了一块,不是完全二叉树了),倒数第二层叶子结点右边连续。
- 注意和满二叉树区分,如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。
- X个结点的完全二叉树,深度为(log2X)+1
- 第X个元素(X表示二叉树的第几个元素,从0开始)的左子节点为2X+1,右子节点为2X+2,父节点为(X-1)/2.
- 总结点个数为total,当前结点下标为X,如果2X>total,则结点没有左子树,否则左子结点为2X,同理,2X+1>total,没有右子树否则2X+1是右子树
- 前序遍历:先输出父节点,再遍历左子树和右子树
- 中序遍历:先遍历左子树,再输出父节点,再遍历右子树
- 后序遍历:先遍历左子树,再遍历右子树,最后输出父节点
如果看不懂上面满二叉树和完全二叉树的区别,可以往下看 |
---|
- 仔细看满二叉树的编号,数字是一直连续的。它也是一棵完全二叉树。
- 而下面的完全二叉树,编号也要连续,并且同一个结点的编号和满二叉树一模一样,这就是完全二叉树。也就是编号连续,并且编号相同的结点和满二叉树相同。但是它的结点个数可能比满二叉树少。
- 因此说,满二叉树一定是完全二叉树,但是完全二叉树不一定是满二叉树。因为只要编号是连续的,同一个编号的结点和满二叉树相同,就可以称为是完全二叉树。
- 完全二叉树很重要,因为它可以无压力的表示在数组中,因为编号连续(下标)
二叉树的一种,保留二叉树的概念和每个结点最多两个子结点的特性。但是二叉搜索树有特别的额外规定
- 每个结点的左子结点,要比当前结点小,也就是左子树都是更小的
- 每个结点的右子结点,要比当前结点大,右子树都是更大的
二叉搜索树的代码实现如下:
- 效果
- 测试方法:我们想让这颗二叉树,能通过泛型,不局限与特定一种数据类型。所以需要用户根据自己使用的数据类型,自定义排序逻辑
- 树节点
- 添加结点操作
- 中序查找和中序遍历,前序和后序,就是代码位置发生了变化而已
- 删除:分为删除根结点和删除非根结点两种,删除根结点要在二叉树中,非根结点就在树结点类中完成。比较复杂的是,删除结点后,被删除结点的子树如何处理。具体大家直接看代码吧(代码在下面给出),图片这里就理一下逻辑。
package com.yzpnb.data_structures.tree.binary_search_tree;
import java.util.Comparator;
public class BinarySearchTree<E> {
private static class TreeNode<E> {
TreeNode<E> leftNode;
E data;
TreeNode<E> rightNode;
TreeNode(TreeNode<E> leftNode,E data,TreeNode<E> rightNode){
this.leftNode = leftNode;
this.data = data;
this.rightNode = rightNode;
}
public void add(E e, Comparator<? super E> c){
if(c.compare(e,data)>=0){
if(leftNode == null) leftNode = new TreeNode<E>(null,e,null);
else leftNode.add(e,c);
}else{
if(rightNode == null) rightNode = new TreeNode<E>(null,e,null);
else rightNode.add(e,c);
}
}
void add(TreeNode<E> e, Comparator<? super E> c){
if(c.compare(e.data,data)>=0){
if(leftNode == null) leftNode = e;
else leftNode.add(e,c);
}else{
if(rightNode == null) rightNode = e;
else rightNode.add(e,c);
}
}
public TreeNode<E> deleteOne(E e,Comparator<? super E> c){
TreeNode<E> parent = null;
TreeNode<E> deleted = null;
if(leftNode != null){
if(leftNode.data.equals(e)){
parent = this;
deleted = doDeleteOne(parent,parent.leftNode,true,c);
return deleted;
}else{
deleted = leftNode.deleteOne(e,c);
}
}
if(deleted != null) return deleted;
if(rightNode != null){
if(rightNode.data.equals(e)){
parent = this;
deleted = doDeleteOne(parent,parent.rightNode,false,c);
return deleted;
}else{
deleted = rightNode.deleteOne(e,c);
}
}
return deleted;
}
public TreeNode<E> doDeleteOne(TreeNode<E> parent,TreeNode<E> deleted,boolean leftOrRight,Comparator<? super E> c){
TreeNode<E> left = deleted.leftNode;
TreeNode<E> right = deleted.rightNode;
if(leftOrRight){
parent.leftNode = left;
if(right != null)
parent.add(right,c);
}else{
parent.rightNode = left;
if(right != null)
parent.add(right,c);
}
return deleted;
}
public TreeNode<E> midFind(E e) {
TreeNode<E> node = null;
if(leftNode!=null)
node = leftNode.midFind(e);
if(node != null) return node;
if(data.equals(e))
return this;
if(rightNode!=null)
node = rightNode.midFind(e);
return node;
}
public void midPrint() {
if(leftNode != null) leftNode.midPrint();
System.out.print(" ,"+this);
if(rightNode!=null) rightNode.midPrint();
}
@Override
public String toString() {
return "TreeNode{" +
"data=" + data +
'}';
}
}
private TreeNode<E> root;
Comparator<? super E> c;
public BinarySearchTree(Comparator<? super E> c){
this.c = c;
}
public BinarySearchTree(TreeNode<E> root,Comparator<? super E> c) {
this.root = root;
this.c = c;
}
public boolean isEmpty(){
return root==null?true:false;
}
public boolean isEmptyError(){
if(isEmpty()) {
System.out.println("树为空,无法操作!!!");
return true;
}else{
return false;
}
}
public E addNode(E data){
if(isEmpty())
root = new TreeNode<>(null,data,null);
else {
root.add(data,c);
}
return data;
}
public TreeNode<E> deleteOne(E e){
if(!isEmptyError()) {
TreeNode<E> deleted = null;
if(e.equals(root.data)){
deleted = root;
TreeNode<E> left = root.leftNode,right = root.rightNode;
if(left != null) {
root = left;
if(right != null)
root.add(right,c);
}
else
root = right;
}else{
deleted = root.deleteOne(e,c);
}
if(deleted == null){
System.out.println("没有找到要删除的节点!!!");
return deleted;
}
return deleted;
}
return null;
}
public TreeNode<E> midFind(E e){
if(!isEmptyError()) {
TreeNode<E> node = root.midFind(e);
if( node == null) System.out.println("没找着!!!");
return node;
}
return null;
}
public void midPrint(){
if(isEmptyError()) return ;
System.out.print("中序遍历:{");
root.midPrint();
System.out.println("}");
}
}
package com.yzpnb.data_structures.tree.binary_search_tree;
import java.util.Comparator;
public class Test {
public static void main(String[] args) {
BinarySearchTree<String> binarySearchTree = new BinarySearchTree<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
binarySearchTree.addNode("7");
binarySearchTree.addNode("4");
binarySearchTree.addNode("5");
binarySearchTree.addNode("3");
binarySearchTree.addNode("3");
binarySearchTree.addNode("7");
binarySearchTree.addNode("2");
binarySearchTree.addNode("1");
binarySearchTree.addNode("3");
binarySearchTree.midPrint();
System.out.println("返回data为7的节点:"+binarySearchTree.midFind("7"));
System.out.println("删除data为7的节点"+binarySearchTree.deleteOne("7"));
binarySearchTree.midPrint();
System.out.println("删除data为7的节点"+binarySearchTree.deleteOne("7"));
binarySearchTree.midPrint();
System.out.println("删除data为4的节点"+binarySearchTree.deleteOne("4"));
binarySearchTree.midPrint();
System.out.println("删除data为3的节点"+binarySearchTree.deleteOne("3"));
binarySearchTree.midPrint();
System.out.println("删除data为1的节点"+binarySearchTree.deleteOne("1"));
binarySearchTree.midPrint();
}
}