顺序存储集合ArrayList
public class m19 {
public static void main(String[] args) {
List<Object> nums = new ArrayList<>();
nums.add(0);
nums.add(0);
nums.add(4);
nums.add(2);
nums.add(5);
nums.add(0);
nums.add(3);
nums.add(0);
/*
此时当前集合存在元素
0 0 4 2 5 0 3 0
*/
new m19().numQuest(nums);
for (int i = 0; i < nums.size(); i++) {
System.out.print(nums.get(i) + " ");
// 0 4 2 5 3
}
}
//precondition: nums.size() > 0
//nums contains Integer objects
public void numQuest(List nums) { // 0 0 4 2 5 0 3 0
int k = 0;
Integer zero = new Integer(0);
while (k < nums.size()) {
if (nums.get(k).equals(zero))
nums.remove(k);
k++;
}
}
/*
zero==0,如果get(k)==0,执行remove(k); ;
size==8 ; k==0 , 因此第一次remove(0)
删除索引为0的元素也就是第一个元素0
然后k++, size()--;
此时集合元素为 :[0,4,2,5,0,3,0]
size==7; k==1,因此get(1)==4 !=0
不执行remove();
k++,因没有删除元素,size()不变
此时可以发现
集合元素如果执行remove方法删除一个元素后
后面的索引自动向前补全
也就是说
当删除一个元素后
后面的1个元素会忽略掉不检查是否为0
这是ArrayList顺序存储的一大特性
所以
一旦涉及到删除指定所有元素
建议使用迭代器
*/
}
for循环的执行顺序
class Print {
static boolean out(char c) {
System.out.println(c); // ABDC BDCB
return true;
}
public static void main(String[] argv) {
int i = 0;
for (out('A'); out('B') && (i < 2); out('C')) {
i++;
out('D');
}
/*
for循环的第1项只初始化1次
然后在比较条件
条件符合再进入循环体
执行完循环体后再执行for循环的第3项
*/
}
}
小根堆最大关键字存储的位置
/*
下标从1开始,在含有n个关键字的小根堆(堆顶元素最小)中
关键字最大的记录有可能存储在()位置上
正确答案: D
[n/2]
[n/2]-1
1
[n/2]+2
就是小顶堆
首先要明白:
中括号取整,就是不大于这个数的最大整数
第二要看清下标是从1开始的
那么
1
2 3
4 5 6 7
...............n
n不论是左子树还是右子树
n的父结点一定是 [n/2]
注意中括号的取整规则,正数就是下取整
那么 [n/2] 这个结点还是有 子结点 的
从 [n/2] + 1 开始一直到 n 都是叶子结点
叶子结点就可能会是最大值,所以选D
人家说的是可能
只要具备可能性就行了
堆是一个完全二叉树,最有可能在最后一个父节点的左子树的位置上
因为数组从0开始计数
最后一个父节点所在位置为n/2+1
其左子树位置n/2+2
*/
哈希地址冲突及解决方案
/*
对于线性表(7,34,55,25,64,46,20,10)进行散列存储时
若选用H(K)=K % 9作为散列函数,则计算的散列地址为1的元素有( )个。
正确答案: D
1 2 3 4
4个
分别是:55,64,46,10
这4个数%9的余数都是1
H(K)= K%9,表示除以9的余数
由于地址重叠造成冲突,所以散列存储时,通常还要有解决冲突的办法
比如线性探测再散列
就是发生哈希地址冲突的时候
顺序查看表中下一个单元
知道找到一个空单元或查遍全表
*/
next数值序列
/*
已知串 S = "babab"
其 Next 数值序列为
正确答案: C
01112
01233
01123
01223
其实算这种next值,不用那么麻烦,我看过很多种算法,有的复杂的我都不想看
这里我把我的做法说一遍,相对简单点
首先介绍2个概念,字符串的前缀和后缀
这里的前缀是不包括最后一个字符的子串
后缀是不包含第一个字符的子串
拿题目中的字符串a="babab"举例
首先第一位0,第二位1
这个是固定的
第三位,字符串是“bab”,这时候“bab”的前缀有b,ba
后缀有ab,b
可以看出前后缀 相等的 最长的 字符串只有b
注意是找 相等的 最长的
相等的是前提
因为b的长度是1,所以这里第三位的next值就是1
到了第四位,字符串是“baba”
前缀是b,ba,bab
后缀是aba,ba,a
这里可以看出前后缀相等的最长的字符串是ba,长度是2,因此第四位的next值是2
到了第五位,字符串是“babab”
前缀是b,ba,bab,baba
后缀是abab,bab,ab,b
这里可以看出前后缀相等的最长的字符串是bab
长度是3,因此第五位的next值是3
因此综合起来next值就是0 1 1 2 3,也就是答案C
*/
线性探测法探测次数
/*
哈希查找中k个关键字具有同一哈希值
若用线性探测法将这k个关键字对应的记录存入哈希表中,至少要进行几次探测
正确答案: C
k
k+1
k(k+1)/2
1+k(k+1)/2
问的是“至少”
那么就是没有出现哈希冲突的情况
第一个:直接找到坑,入坑,1次;
第二个:和第一个同hash,找到坑被第一个给占了,找下一个,入坑,2次;
第三个:第一个被占了,第二个也被占了,找第三个,入坑,3次;
... ...
第n个:n次;
一共:(1+n)*n / 2 次
开放地址法(除了随机探测)都是(1+n)*n/2次
线性探测法就是挨个查找
直到找到空位即可
如果n个关键字具有相同的哈希值
那么需要进行n^2次线性探测
这是至多的情况
*/
程序设计题:反转链表
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while(cur!=null){
/*
程序运行到此处
创建辅助节点currentNode
目的在于便于移动cur指针
然后cur点下一个节点指向pre
形成了next指针反向相反方向的情况
也就是next实际上就是链表中的prev指针
*/
ListNode currentNode = cur.next;
cur.next = pre;
pre = cur;
cur = currentNode ;
}
/*
程序运行到此处
cur指针指向null
pre指针指向表尾元素
而pre的next方法指向前一个节点
通过辅助指针反转链表
*/
return pre;
}
}