树的一些概念以及算法小结

树的相关总结

树的基本概念

  1. 合法的树不能形成无出口的回路
  2. n个互斥树的集合是森林
  • 度数:每个节点所有子树的个数
  • 层数:树的层数
  • 高度:树的最大层树。
  • 树叶或成终端节点:度数为0的节点就是树叶
  • 父节点:每一个节点有链接的上一层节点(即为父节点)
  • 子节点:每一个节点有链接的下一层节点为子节点
  • 祖先或子孙:所谓祖先是指从树根到该节点路径上所包含的节点,子孙是该节点往下追溯子树的任一节点
  • 非终端节点:树叶以外的节点
  • 同代:在同一棵中具有相同层数的节点
  • 森林:n个互斥树的集合,移去树根即为森林

树的分类


  • 满二叉树
    高度为h,树的节点数为 2 h − 1 2^h-1 2h1,则“满二叉树”。
  • 完全二叉树
    对于完全二叉树而言,假设有 N N N个节点,那么此二叉树的层数为h为 l o g 2 ( N + 1 ) log_2(N+1) log2(N+1)
  • 斜二叉树
    完全没有右节点或左节点
  • 严格二叉树
    二叉树中的每一个非终端节点均有非空的左右子树
  • eg:
    假如有一个非空树,其度数为5,已知度数为i的节点数有i个,其中 1 < = i < = 5 1<=i<=5 1<=i<=5,终端节点的个数?
    41

数组表示二叉树

import java.io.*;
import java.lang.reflect.Array;
import java.util.Arrays;

public class ch06_1 {
    public static void main(String[] args){
        int level;
        int data[]={6,3,5,9,7,8,4,2};
        int btree[]=new int[16];
        Arrays.fill(btree,0);
        System.out.println("原数组内容");
        for(int i:data)
        {
            System.out.print("["+i+"] ");
        }
        for(int i=0;i<8;i++){ // 原始数组的值逐一对比
            for(level=1;btree[level]!=0;){ //比较树根及数组内的值
                if(data[i]>btree[level])  //如果大于树根则往右子树比较 
                    level=level*2+1;
                else //如果数组内的值小于树根则往左子树比较
                    level=level*2;
            }
            btree[level]=data[i]; //数组值放入二叉树
        }
        System.out.println("二叉树的内容");
        for(int i=1;i<16;i++){
            System.out.print("["+btree[i]+"] ");
        }
    }
}

链表表示二叉树

import java.io.*;
class TreeNode{
    int value;
    TreeNode left_Node;
    TreeNode right_Node;
    public TreeNode(int value){
        this.value=value;
        this.left_Node=null;
        this.right_Node=null;
    }
}
class BinaryTree{
    public TreeNode rootNode;
    public BinaryTree(int[] data){
        for(int i=0;i<data.length;i++){
            Add_Node_To_Tree(data[i]);
        }
    }
    void Add_Node_To_Tree(int value){
        TreeNode cur=rootNode;
        if(rootNode==null)
        {
            rootNode=new TreeNode(value);
            return;
        }
        while (true){
            if(value<cur.value){
                if(cur.left_Node==null){
                    cur.left_Node=new TreeNode(value);
                    return;
                }
                else cur=cur.left_Node;
            }
            else {
                if(cur.right_Node==null)
                {
                    cur.right_Node=new TreeNode(value);
                    return;
                }
                else cur=cur.right_Node;
            }
        }
    }
}
public class ch06_2 {
    public static void main(String[] args) throws IOException{
        int Arraysize=10;
        //int tmpData;
        int[] content=new int[Arraysize];
        BufferedReader keyin=new BufferedReader(new InputStreamReader(System.in));
        System.out.println("连续输入"+Arraysize+"个数据");
        for(int i=0;i<Arraysize;i++){
            System.out.println("请输入第"+(i+1)+"个数据");
            content[i]=Integer.parseInt(keyin.readLine());
        }
        new BinaryTree(content);
        System.out.println("二叉树建立完成");
    }

}

二叉树的遍历

1. 前序遍历

ABC:树根->左子树->右子树

    public void PreOder(TreeNode node){
        if(node!=null)
        {
            System.out.print("["+node.value+"] ");
            PreOder(node.left_Node);
            PreOder(node.right_Node);
        }
    }
2. 中序遍历

BAC:左子树->树根->右子树

    public void InOder(TreeNode node) {
        if (node != null)
        {
            InOder(node.left_Node);
            System.out.print("["+node.value+"] ");
            InOder(node.right_Node);
        }
    }
3. 后序遍历

BCA:左子树->右子树->树根

    public void PostOder(TreeNode node){
        if(node!=null){
            PostOder(node.left_Node);
            PostOder(node.right_Node);
            System.out.print("["+node.value+"] ");
        }
    }

二叉运算树

  1. 考虑表达式中运算符的结核性和优先权,再适当地加上括号
  2. 再由最内层的括号逐步向外,利用运算符当树根,左边操作数当左子树,右边操作数当右子树,其中优先权最低的运算符作为次二叉运算树的树根。
//在BinaryTree需要补上 public BinaryTree(){rootNode=null;};
class Expression_Tree extends BinaryTree{
    public Expression_Tree(char[] information,int index){
        rootNode =create(information,index);
    }
    public TreeNode create(char[] sequence,int index){
        TreeNode tmpNode;
        if(index>=sequence.length)
            return null;
        else {
            tmpNode=new TreeNode((int)sequence[index]);
            //建立左子树
            tmpNode.left_Node=create(sequence,2*index);
            //建立右子树
            tmpNode.right_Node=create(sequence,2*index+1);
            return tmpNode;
        }
    }
    public void InOder(TreeNode node) {
        if (node != null)
        {
            InOder(node.left_Node);
            System.out.print((char)node.value);
            InOder(node.right_Node);
        }
    }
    public void PreOder(TreeNode node){
        if(node!=null)
        {
            System.out.print((char)node.value);
            PreOder(node.left_Node);
            PreOder(node.right_Node);
        }
    }
    public void PostOder(TreeNode node){
        if(node!=null){
            PostOder(node.left_Node);
            PostOder(node.right_Node);
            System.out.print((char)node.value);
        }
    }
    public int condition(char oprator,int num1,int num2) {
        return switch (oprator) {
            case '*' -> num1 * num2;
            case '/' -> num1 / num2;
            case '+' -> (num1 + num2);
            case '-' -> (num1 - num2);
            case '%' -> (num1 % num2);
            default -> -1;
        };
    }
    public int answer(TreeNode node) {
        int firstnumber = 0;
        int secondnumber = 0;
        if (node.left_Node == null && node.right_Node == null)
            return Character.getNumericValue((char) node.value);
        else {
            firstnumber = answer(node.left_Node);   //计算左子树表达式的值
            secondnumber = answer(node.right_Node); //计算右子树表达式的值
            return condition((char) node.value, firstnumber, secondnumber);
        }
    }
}
public class ch06_4 {
    public static void main(String[] args){
        char[] information1={' ','+','*','%','6','3','9','5'};
        char[] information2={' ','+','+','+','*','%','/','*','1','2','3','2','6','3','2','2'};
        Expression_Tree exp1=new Expression_Tree(information1,1);
        System.out.println("例1:");
        System.out.println("============");
        System.out.println("\n转换为中序表达式");
        exp1.InOder(exp1.rootNode);
        System.out.println("\n转换为前序表达式");
        exp1.PreOder(exp1.rootNode);
        System.out.println("\n转换为后序表达式");
        exp1.PostOder(exp1.rootNode);

        System.out.println("\n此二叉运算树,经过计算后的结果:");
        System.out.println(exp1.answer(exp1.rootNode));

        Expression_Tree exp2=new Expression_Tree(information2,1);
        System.out.println("例2:");
        System.out.println("=============");
        System.out.println("\n转换成中序表达式:");
        exp2.InOder(exp2.rootNode);
        System.out.println("\n转换成前序表达式:");
        exp2.PreOder(exp2.rootNode);
        System.out.println("\n转换成后序表达式:");
        exp2.PostOder(exp2.rootNode);

        System.out.println("\n此二叉运算树,经过计算后的结果:");
        System.out.println(exp1.answer(exp2.rootNode));
    }
}

二叉排序树

  1. 第一个输入的数据为树根
  2. 后面输入的数据跟树根比较,小于树根置于左子树,大于树根置于右子树
    同前文所提出的例程已经是 排序树
    中序遍历后 即为从小到大排列
    和二叉搜索树没啥区别

线索二叉树

就是在上述二叉树的基础上 加入两个属性 标记有否有左右子树
能加快中序遍历的速度

一般树和二叉树的转换

  • 一般的树转换为二叉树
  1. 将节点的所有兄弟节点,用横线链接起来
  2. 删掉所有与子节点之间的链接,仅保留与最左边子节点的链接
  3. 顺时针旋转45°
  • 二叉树转换为一般的树
    上述步骤反过来操作
  • 森林转换为二叉树
  1. 将各树的树根从左向右链接
  2. 基于将一般树转换为二叉树的步骤进行
  • 上述步骤反过来

确定唯一二叉树

比较常见的考题
比如给了中序和前序遍历 求出二叉树等等


扩充二叉树

任何一个二叉树中 若有n个节点 则有n-1个非空链接和n+1个空链接
定义:外径长=所有外节点到树根距离的总和,内径长=所有内节点到树根距离的总和


霍夫曼树

  1. 产生两个节点,对数据中出现过的每一元素各自产生一个树叶节点,并赋予树叶节点该元素出现的频率
  2. 令N为 T 1 T_1 T1 T 2 T_2 T2的父节点, T 1 T_1 T1 T 2 T_2 T2是T中出现频率最低的两个节点,令N节点的出现频率等于 T 1 T_1 T1 T 2 T_2 T2出现频率的总和.
  3. 去掉步骤的两个节点,插入N,重复第一步

平衡树

又称AVL树
T是一个非空二叉树,Tl和Tr是它的左右子树
满足以下两个条件:

  • Tl和Tr也是高度平衡的
  • ∣ h l − h r ∣ ⩽ 1 |h_l-h_r| \leqslant 1 hlhr1, h l , h r h_l,h_r hl,hr分别是Tl和Tr的高度

B树/B tree

高度大于等于1的m阶搜索树

  1. B树上的每一个节点都是m阶节点
  2. 每一个m阶节点存放的键值最多为m-1个
  3. 每一个m阶节点的度数均小于等于m
  4. 除非是 空树 根节点至少有两个以上的子节点
  5. 除了树根和树叶子节点置为 每一个节点最多不超过m个子节点 但至少包含你m/2个子节点
  6. 每个树叶子节点到树根节点所经过的路径长度一致 也就是说所有树子节点都必须在同一层
  7. 当要增加数的高度时 处理方法是将树根节点一分为二
  8. B树其键值分别为k1,…km-1

B+树

1.根结点至少有两个子女。

2.每个中间节点都至少包含ceil(m / 2)个孩子,最多有m个孩子。

3.每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m。

4.所有的叶子结点都位于同一层。

5.每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。

B+树与B树的区别

  • 有k个子结点的结点必然有k个关键码;
  • 非叶结点仅具有索引作用,跟记录有关的信息均存放在叶结点中。
  • 树的所有叶结点构成一个有序链表,可以按照关键码排序的次序遍历全部记录。
    (这一段来源:作者:CPinging 链接:https://www.jianshu.com/p/71700a464e97 )

PS:以上内容参考自《图解数据结构》

红黑树

基于二叉查找树

  1. 红链接均为左链接
  2. 没有任何 一个节点同时和两条红链接相连
  3. 概述是完美黑色平衡的 任意空连接到根节点的路径上的黑连接适量相同

性质1:每个节点要么是黑色,要么是红色。
性质2:根节点是黑色。
性质3:每个叶子节点(NIL)是黑色。
性质4:每个红色结点的两个子结点一定都是黑色。
性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。

左子节点为黑色 右子节点为红色 此时需要左旋
左子节点为红色 且左子节点的左子节点也为红色 此时需要右旋
(这一段来源:作者:安卓大叔链接:https://www.jianshu.com/p/e136ec79235c )

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值