递归树
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个
*/