几个重要知识点补充
LinkedList
如何体现双向链表?
void addFirst() 将指定元素插入开头
void addLast() 将指定元素添加到结尾
E getFirst() 返回列表的第一个元素
E getLast() 返回列表的最后一个元素
boolean offer(E e) 将元素添加到列表的末尾(最后一个元素)
boolean offerFirst(E e) 将元素添加到列表的开头
boolean offerLast(E e) 将元素添加到列表的结尾
int indexOf(Object o) 返回列表中首次出现该元素的索引,没有返回-1
int lastIndexOf(Object o) 返回列表中最后出现该元素的索引,没有返回-1
E get(int index) 返回指定位置的元素
如何体现栈?
void push(E e) 将元素推入列表所表示的堆栈
E peek() 获取但不移除(第一个元素)
E peekFirst() 获取但不移除第一个元素
E peekLast() 获取但不移除最后一个元素
E pop() 弹出一个元素
如何体现队列?实现Queue接口
| 抛出异常 | 返回特殊值 | |
|---|---|---|
| 插入 | add(e) | offer(e) |
| 移除 | remove() | poll() |
| 检查 | element() | peek() |
如何体现双端队列?实现Deque接口
| 抛出异常 | 返回特殊值 | |
|---|---|---|
| 插入第一个 | addFirst(e) | offerFirst(e) |
| 插入最后 | addLast(e) | offerLast(e) |
| 移除第一个 | removeFirst() | pollFirst() |
| 移除最后一个 | removeLast() | pollLast() |
| 检查第一个 | getFirst() | peekFirst() |
| 检查最后一个 | getLast() | peekLast() |
不需要线程安全时:Deque deque = new LinkedList<>();
优先队列PriorityQueue
Queue接口的实现,可以对其中元素进行排序,默认是升序排列
常用方法
peek(); //返回队首元素
poll(); //返回队首元素,队首元素出队列
add(); //添加元素
size(); //返回元素个数
isEmpty(); //判断队列是否为空
Comparator接口的Lambda表达式
o1-o2是升序,o2-o1是降序
//1.方法1:
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
//intervals数组按升序排列
// 2. 方法2:
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int o1[], int o2[]) {
return o1[0] - o2[0];
}
});
//二维数组降序排列:
Arrays.sort(people, (o1, o2) -> o1[0] == o2[0] ? o1[1] - o2[1]: o2[0] - o1[0]);
位运算
位操作符
- &与运算
- 两个都为1——1
- |或运算
- 有一个为1——1
- ^异或运算
- 两位不同——1
- ~取反运算
- 是0——1
- 左移运算
- 高位丢弃,低位补0
- 右移运算
- 无符号数,高位补0
- 有符号数,高位补符号数
常见位运算问题
-
a向右移一位——a/2,向下整除
-
a向左移一位——a*2
-
异或操作交换两数
void swap(int a, int b){ a ^= b; b ^= a; a ^= b; } -
判断奇偶数
和1与操作,为1就是奇数,为0就是偶数
if(0 == (a&1)){ //偶数 } //所以也可以用来求n%2的余数 -
交换符号
int reversal(int a){ return ~a+1; } -
求绝对值
先判断符号:整数右移31位是0,负数右移31位是-1
整数绝对值是本身,负数绝对值是交换符号的本身
int abs(int a){ int i = a>>31; return i == 0? a : (~a+1); }
Java各类型转换
StringBuilder ---> String
String str = "awswondeoifoivnfr";
StringBuilder sb = new StringBuilder(str);
整型数组 ----> 字符串
StringBuilder sb = new StringBuilder();
for(int i=i; i<n; i++){
s.append(String.valueOf(a[i]));
}
String str = "" + sb;
字符串 ----> 整型数组
String str = "123456";
int[] a = new int[str.length()];
for(int i=0; i<str.length(); i++){
a[i] = str.charAt(i) - '0';
}
字符串 ----> 字符数组
char[] c = str.toCharArray();
字符数组 ----> 字符串
String str = new String(c);
字符数组 ----> 整型数组
char[] c = {'1', '2', '3', '4'};
int[] a = new int[c.length];
for(int i=0; i<c.length; i++){
a[i] = c[i] - '0';
}
整型数组 ----> 字符数组
int[] a = {1,2,3,4,5};
char[] c = new char[a.length];
for(int i=0; i<a.length; i++){
c[i] = (char)(a[i] + '0');
}
整型数 ----> 字符串
//1
String str = Integer.toString(i);
//2
String str = String.valueOf(i);
//3
String str = "" + i;
//Double, Float, Long 同理
字符串 ----> 整型数
//1
int i = Integer.parseInt(String);
//2
int i = Integer.valueOf(str).intValue();
//Double, Float, Long 同理
数据类型
一个字节是8位
- int
- byte(8 bits) short(16 bits) int(32 bits) long(64 bits)
- float
- 单精度(32bits float) 双精度(64bits double)
- char
- 16bits
- boolean
- 8 bits
转换原则
从低到高
byte -> short -> int -> long -> float -> double -> char
List ----> Array
List<String> list = new ArrayList<>();
Object[] array = list.toArray(new String[List.size()]);//直接指定类型。防止强制转换时抛异常
Array ----> List
List<String> list = new ArrayList<String>(Arrays.asList(array));
KMP算法
有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢?
暴力匹配
假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有:
- 如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符;
- 如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯,j 被置为0。
KMP算法(Knuth-Morris-Pratt三个人)
假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置
- 如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;
- 如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j - next [j] 位。
next数组
next[i]表示的是前i的字符组成的这个子串最长的相同前缀后缀的长度
对于每模式串 t 的每个元素 t j,都存在一个实数 k ,使得模式串 t 开头的 k 个字符(t 0 t 1…t k-1)依次与 t j 前面的 k(t j-k t j-k+1…t j-1,这里第一个字符 t j-k 最多从 t 1 开始,所以 k < j)个字符相同。如果这样的 k 有多个,则取最大的一个。
void Getnext(int next[],String t)
{
int j=0,k=-1;
next[0]=-1;
while(j<t.length-1)
{
if(k == -1 || t[j] == t[k])
{
j++;k++;
if(t[j]==t[k])//当两个字符相同时,就跳过
next[j] = next[k];
else
next[j] = k;
}
else k = next[k];
}
}
KMP的实现
int KMP(String s,String t)
{
int next[MaxSize],i=0;j=0;
Getnext(t,next);
while(i<s.length&&j<t.length)
{
if(j==-1 || s[i]==t[j])
{
i++;
j++;
}
else j=next[j]; //j回退。。。
}
if(j>=t.length)
return (i-t.length); //匹配成功,返回子串的位置
else
return (-1); //没找到
}
Iterator迭代器
迭代器可以遍历并选择序列中的对象,被称为“轻量级”对象
功能简单,并且只能单向移动
- 第一次调用next()方法时,返回序列的第一个元素
- next()获得序列的下一个元素
- hasNext()检查序列中是否还有元素
- remove()将迭代器新返回的元素删除
public static void main(String[] args){
List<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String a = it.next();
System.out.println(a);
if("bbb".equals(a)){
it.remove();
}
}
}
功能更强大的ListIterator
- 可以向前、向后两个方向遍历List
- 在遍历时可以修改List的元素
- 遍历时获取迭代器当前游标所在位置(迭代器没有当前元素,只有游标一个概念,在元素之间)
新增方法
- void hasPrevious() 判断游标前面是否有元素
- Object previous() 返回游标前面的元素,同时游标前移
- int nextIndex() 返回游标后边元素的索引位置,初始为0
- int previousIndex() 初始为-1,同时报错
- void add(E) 在游标前面插入一个元素
- void set(E) 更新迭代器最后一次操作的元素为E,即上一个调用next()或previous()返回的元素
- void remove() 删除迭代器最后一次操作的元素
要实现由后向前的遍历,应先实现由前向后的遍历
单例模式
单例最重要的思想:构造器私有,别人就无法new这个对象了
饿汉式单例
public class Hungry{
private Hungry(){
}
//饿汉式·一上来就把这个对象加载了:
private final static Hungry HUNGRY = new Hungry();//先new一个hungry出来,这个是唯一的
//可能会浪费空间
public static Hungry getInstance(){
return HUNGRY;
}
}
懒汉式单例
public class LazyMan{
private LazyMan(){
//为防止反射破坏
synchronized(LazyMan.class){
if(lazyMan!=null){
throw new RuntimeException("不要试图使用反射!");
}
}
}
private volatile static LazyMan lazyMan;//避免new LazyMan()指令重排
public static LazyMan getInstance(){
if(lazyMan == null){
lazyMan = new LazyMan();//不是原子性操作
}
return lazyMan;
}
//单线程没问题
//多线程并发需要加锁
public static LazyMan getInstance(){
//双层检测锁模式的懒汉式单例 DCL懒汉式
if(lazyMan==null){
synchronized(LazyMan.class){
if(lazyMan==null){
lazyMan = new LazyMan();
}
}
}
return lazyMan;
}
//反射可以破坏单例
public static void main(String[] args){
LazyMan instance = LazyMan.getInstance();
Constructor<LazyMan> deCon = LazyMan.class.getDeclaredConstructor(null);//get空参构造器
deCon.setAccessible(true);//无视了私有构造器
LazyMan instance2 = deCon.newInstance();//通过反射创建对象
//instance和instance2已经不是同一个了,违背了单例
}
}
静态内部类
public class Holder{
private Holder(){
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new holder();
}
}
单例不安全,因为有反射
使用枚举
枚举
public enum Direction{
FRONT, BEHIND, LEFT, RIGHT;//都是本类的实例,一共有四个实例对象
}
Direction d = Direction.FRONT;//类名.枚举项,不能使用new创建对象
枚举和switch
enum Signal{
RED, YELLOW, GREEN;
}
public static String getTrafficInstruct(Signal signal){
String instruct = "信号灯故障";
switch(signal){
case RED:
instruct = "红灯停";
break;
case YELLOW:
instruct = "黄灯";
break;
case GREEN:
instruct = "绿灯行";
break;
default:
break;
}
return instruct;
}

浙公网安备 33010602011771号