Map映射

操作

根据键来找值(键值对)
key不可重复,value可以

Hashmap

定义

一个数组装着各个链表的头节点,通过计算一个元素的哈希值,找到数组下标,并在对应链表后面增加一个新的节点。

扩容

第一次使用时初始化,在必要时进行扩容,且大小永远是2的倍数(power of 2)

如果只扩容链表长度,查询速度将会越来越慢–>增长数组长度可以解决这个问题

当一支链表(单链表)长度过长(大于8),使用红黑树(JDK1.8以上)。数组存放根节点,二分查找提升查找速率,而且旋转次数比平衡二叉树少。

负载因子

用于判断挡前是否需要进行扩容

插入新的元素之后,当前的数组占用率到达n%以上则需要扩容

扩容时会重新计算所有元素的哈希值,得到新的下标并得到新的哈希表。

默认0.75

LinkedHashmap

普通的Hashmap的存放顺序和输入顺序是没有关系的,按照哈希值的计算结果摆放,而LinkedHashmap记录的before和after即存放的前后关系,每一个节点都是双向链表。

访问顺序(accessOrder)可以使得最近访问过的元素放在最后。

Treemap

自动维护顺序的一种map,可以看作是在维护一颗红黑树

stream流

比较像流水线,通过链式调用,持续操作。对数据有大量复杂连续操作时使用。

流在运行时会先记录所有步骤,建立完整流水线再进行操作

summaryStatistics.getMax()//统计类

stream一般不返回直接结果,而是返回optional类,这样是为了避免空指针出现异常

数组工具Arrays

操作数组不像集合那样方便,所以提供操作数组的工具方法

public static void main(String[] args) {
    int[] array = {1, 5, 2, 4, 7, 3, 6};
    Arrays.sort(array);   //直接进行排序(底层原理:进行判断,元素少使用插入排序,大量元素使用双轴快速/归并排序)
    System.out.println(array);  //由于int[]是一个对象类型,而数组默认是没有重写toString()方法,因此无法打印到想要的结果
    System.out.println(Arrays.toString(array));  //我们可以使用Arrays.toString()来像集合一样直接打印每一个元素出来
    
    Arrays.sort(array);
    System.out.println("排序后的结果:"+Arrays.toString(array));
    System.out.println("目标元素3位置为:"+Arrays.binarySearch(array, 3));  //二分搜素,必须是已经排序好的数组!
    
    
    //array array2为多维数组
    System.out.println(Arrays.deepToString(array));   //使用deepToString就能到打印多维数组
    System.out.println(Arrays.deepEquals(array2, array));   //使用deepEquals就能比较多维数组
}

print只能打印String
Arrays.asList()来将数组转换为一个 固定长度的List 不可使用add和remove等

集合类也有相关的简化操作工具Collections

集合类

集合类其实就是为了更好地组织、管理和操作我们的数据而存在的,包括列表、集合、队列、映射等数据结构。

集合类最顶层不是抽象类而是接口,因为接口代表的是某个功能,而抽象类是已经快要成形的类型,不同的集合类的底层实现是不相同的,同时一个集合类可能会同时具有两种及以上功能(既能做队列也能做列表),所以采用接口会更加合适,接口只需定义支持的功能即可。

Java收集包中的所有类_数组

小测试

反转链表

思考操作元素的位置:先走到表尾,再依次回到表头
类似递归概念,故考虑使用递归方法。

public static Node reverse(Node head) {
		//在这里实现
		if (head.next == null){
			return head;
		}

		Node result = reverse(head.next);
		head.next.next = head;
		head.next = null;//这一行自己没想到
		return result;
	}

重建二叉树

描述:给出前序、中序,还原整个二叉树。
前序遍历:可以直接得到根节点的位置
中序遍历:通过得到的根节点的值,找到根节点的位置,得到左子树节点值,从而依次找到新的根节点的位置。

步骤

1.得到根节点的值
2.得到根节点的位置
3.将根节点左右序列分开,并重构为根节点的左右子树
4.在新的序列中重复上述步骤,直到分割到只剩下一个节点时开始回溯,重建整个二叉树

实现计算器

实现包含加减乘除、小数的计算公式的计算

步骤

使用两个栈,一个存放数字,一个存放运算。依次存放数字和运算符,当存放下一个运算符时,栈中已有两个数字和一个运算符,且下一个运算符的优先级小于等于上一个时进行运算,将结果放入数字栈中。

细节

//Deque
private static Deque<Character> opr = new LinkedList<>();

双端队列,两头均可进和出。
Character 是 char 对应的包装类,JDK1.5以后可以自动封装自动解封,

char ch='a';

Character ch1=ch;//自动封箱

Character c=new Character(a);

char c1=c;//自动解封

使用封装类可以获得更多的方法。
同理还有double和Double、long和Long

(str[i]-'0')

可以获得该char对应的数字

import java.util.*;
import java.util.LinkedList;
import java.util.stream.Collectors;
public class RebuildTree {
	private static Deque<Character> opr = new LinkedList<>();
	private static Deque<Double> number = new LinkedList<>();

	public static void main(String[] args){
		Scanner scanner = new Scanner(System.in);
		String formula = scanner.nextLine();
		char[] str = formula.toCharArray();
		int i = 0;
		while(i < str.length){
			char c = str[i];
			if(isOpr(c)){
				Character peek = opr.peek();
				while (peek != null && isHigherOpr(peek, c)){
					cal();
					peek = opr.peek();

				}
				opr.push(c);
				i++;
			}
			else{
				double tempNum = 0;
				//小数分开
				double tempNum2 = 0;
				int times = 1;//小数位数
				boolean flag = Boolean.FALSE;
				//限制长度
				while(i < str.length && !isOpr(str[i])){
					if(str[i] == '.')flag = Boolean.TRUE;
					else{
						if(!flag){
							tempNum = tempNum * 10 + (str[i] - '0');
						}
						else{
							double val = str[i]-'0';

							for(int j =0; j < times; j++)val /= 10;
							tempNum2 = tempNum2 + val;
							times ++;
						}

					}
					i ++;
				}
				number.push(tempNum + tempNum2);

			}


		}
		while(!opr.isEmpty()) cal();
		System.out.println(number.peek());






	}
	private static boolean isHigherOpr(char peek, char c){
		//True 则需要做运算
		return (c == '+' || c == '-') || (peek == '*' || peek == '/');
	}
	private static boolean isOpr(char c){
		return c == '+' || c == '-' || c == '*' || c == '/';
	}

	private static void cal(){
		double a = number.pop();
		double b = number.pop();
		char c = opr.pop();

		switch (c){
			case '+':
				number.push(a + b);
				break;
			case '-':
				number.push(b - a);
				break;
			case '*':
				number.push(a * b);
				break;
			case '/':
				number.push(b / a);
				break;

		}


	}
}

字符串匹配–KMP算法