X32专项练习部分19

这篇博客详细介绍了Java中数据结构的相关概念,包括递归树、完全二叉树的两种情况、链地址法解决哈希冲突,以及值类型和引用类型的差异。此外,还探讨了初始建堆和push操作在堆数据结构中的应用,instanceof关键字在多态机制中的作用,以及如何通过节点度数判断二叉树的叶子节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

递归树

class Test {
    public static int count = 0;

    public static void main(String[] args) {
        int i;
        i = x(8);
        System.out.println(count); // 9
    }

    public static int x(int n) {
        count++;
        if (n <= 3)
            return 1;
        else
            return x(n - 2) + x(n - 4) + 1;
    }
    /*
    count的作用是统计递归次数
    共有几个递归程序进入x方法体

    以8为根节点画出递归树
    8个分支表明调用8次
    再加上自身调用x(8)一次
    共9次
                  8
            6           4
        4      2    2       0
    2      0

     */
}

完全二叉树两种情况

/*
已知一棵完全二叉树的第6层(设根为第1层)有8个叶结点
则该完全二叉树的结点个数最多是()。
正确答案: C   你的答案: 空 (错误)
39
52
111
119

完全二叉树比满二叉树只是在最下面一层的右边缺少了部分叶结点
也就是说完全二叉树最后2层都有可能是叶子节点

两种情况
第六层或者第七层是最后一层
第七层是最后一层时完全二叉树的结点个数最多
此时 第六层总2^(6-1) = 32个结点中有8个是叶子节点
前5层最多一共有16+8+4+2+1 = 31个节点

则第六层中另外24个结点都有孩子 而满足结点数最多 则第七层共有24*2=48个结点
总结点数就是63+48=111
 */

链地址法解决哈希冲突

/*
设哈希表长为8,哈希函数为Hash (key)=key%7。初始记录关键字序列为(32,24,15,27,20,13)
用链地址法作为解决冲突方法的平均查找长度是
正确答案: B
1.4
1.5
1.6
1.7

    链地址法作为解决冲突方法:冲突以后变成链表,查询次数增加
    32%7=4(查一次)
    24%7=3(查一次)
    15%7=1(查一次)
    27%7=6(查一次)
    20%7=6(查两次)
    13%7=6(查三次)
    ASL(平均查找长度) = (1*4+2*1+3*1)/6=1.5
    
    哈希表长度为8,故存储的位置分别是0、1、2、3、4、5、6、7
    根据哈希函数
    可以得到关键字序列(32,24,15,27,20,13)存储的位置分别为:4、3、1、6、6、6
    
    解决冲突的方式是链地址法
    故20和13存储在27的下边,三者构成一个链表结构
    第一个元素为27,最后一个元素为13.
    哈希表中查找一个元素的复杂度为O(1)
    故32、24、15、27分别查找一次即可找到
    而20和13在链表结构中,需要从27开始往下遍历
    分别需要额外的一次和两次才能找到,即20需要两次,13需要三次。
    故最终的平均查找长度为总查询次数 / 关键字个数=(1+1+1+1+2+3)/ 6 = 1.5
 */

值类型和引用类型的区别

/*
下列说法错误的是

正确答案: B
struct声明的类型是值类型
值类型是在堆上分配的
值类型不会被垃圾回收
值类型不需要指针来引用
引用类型在堆上分配,值类型在栈上分配

值类型和引用类型的区别

存储方式
值 直接存储数据本身
引 存储的是数据的引用,数据存储在数据堆中

内存分配
值 分配在栈中的
引 分配在堆中

效率
值 效率高,不需要地址转换
引 效率较低,需要进行地址转换

内存回收
值 使用完后立即回收
引 使用完后不立即回收,而是交给GC处理回收

赋值操作
值 创建一个新对象
引 创建一个引用

类型扩展
值 不易扩展,所有值类型都是密封(seal)的,所以无法派生出新的值类型
引 具有多态的特性方便扩展

实例分配
值 通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中
引 总是在进程堆中分配(动态分配)
 */

初始建堆及针对堆的push操作

/*
堆的数据结构能够使得堆顶总是维持最大(对于大根堆)或最小(对于小根堆)
给定一个数组,对这个数组进行建堆,则平均复杂度是多少?
如果只是用堆的 push 操作,则一个大根堆依次输入 3,7,2,4,1,5,8 后,
得到的堆的结构示意图是下述图表中的哪个?()

初始建堆的时间复杂度为O(n)
不过题目说明只是用堆的push操作
所以需要边插入边调整

指定区间的最后一个元素加入堆中并使整个区间成为一个新的堆
注意前提是新加入的最后一个元素除外的所有元素已经构成一个堆
 */

在这里插入图片描述

instanceof触发多态机制

class Test4 {
    public static void main(String args[]) {
        List  Listlist1 = new ArrayList();
        Listlist1.add(0);
        List Listlist2 = Listlist1;
        System.out.println(Listlist1.get(0) instanceof Integer); // true
        System.out.println(Listlist2.get(0) instanceof Integer); // true
    }
    /*
    List集合中的元素必须是对象。
    Listlist1.add(0);
    JDK1.5之后支持自动装箱(int类型自动装箱成Integer),编译通过

    instanceof
    前一个参数通常是一个引用类型变量,后一个操作数通常是一个类
    也可以是一个接口
    它用于判断前面的对象是否是后面的类,或者其子类、实现类的实例

    List没有使用泛型
    说明使用get(0)取出的元素的编译类型是Object型的

    instanceof用于判断是否是某一特定类的实例
    运行时类型是Integer
    所以打印true
    这边体现了多态
    而Listlist1把引用赋给了List list2,说明两个指向同一个对象
    第二个打印的也是true
     */
}

类的初始化过程

class C {
    C() {
        System.out.print("C");
    }
}

class A {
    C c = new C();

    A() {
        this("A");
        System.out.print("A");
    }

    A(String s) {
        System.out.print(s);
    }
}

class Test5 extends A {
    Test5() {
        super("B");
        /*
        这里需要注意
        子类构造器第1行编译器会默认添加super();

        由于已经显式调用父类带参构造函数super("B");
        所以子类调用的父类构造器是A(String s)
        而不是无参构造器
        除非在子类构造器里没有显式调用父类构造器
        编译器才在子类构造器为其默认添加super();
         */
        System.out.print("B");
    }

    public static void main(String[] args) {
        new Test5();
    }
    /*
    初始化过程是这样的:
    1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
    2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
    3.其次,初始化父类的普通成员变量和代码块,在执行父类的构造方法;
    4.最后,初始化子类的普通成员变量和代码块,在执行子类的构造方法;

    (1)初始化父类的普通成员变量和代码块,执行 C c = new C(); 输出C
    (2)super("B"); 表示调用父类的有参构造方法
        不调用父类的无参构造函数,输出B
        所以此时父类无参构造方法存在是没有必要的
    (3)System.out.print("B");
     所以输出CBB
     */
}

通过度判断二叉树的叶子节点

/*
    若一棵二叉树具有8个度为2的结点,5个度为1的结点,则度为0的结点个数是?
        正确答案: B
        6
        9
        11
        不确定

    题中度为2指的是有两个子节点, 度为1是1个子节点
    假设度0的节点有x个
    那个二叉树的边,按照出节点来算个数为
    edges = 8*2 + 5*1 = 21

    按照入节点来算,个数为
    8+5+x-1
    最后减1是根节点

    边是一定的, 所以
    记住以下公式
    edges = allNode - 1

    边的总数 = 所有节点个数减根节点

    8*2 + 5*1 =  8+5+x-1
    x = 9
    
    下面是一个常用的原理
    任何一颗二叉树中,度为0的节点比度为2的节点多一个。因此度为0的节点为9个
     */

总目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

muskfans

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值