这里写目录标题
队列Queue
- Queue(I): - 队列(offer/peek/poll)
- Deque(I) - 双端队列(offerFirst/offerLast…)
- 栈(push/pop)- LinkedList
- Deque(I) - 双端队列(offerFirst/offerLast…)
API
- offer("")进队列
- peek()获取队列头元素
- poll()获取队列头元素,并将元素从队列中移除
// 1.创建队列 - 先进先出
Queue<String> qu = new LinkedList<>();
// 2.进队列的方法
qu.offer("哈哈哈");
qu.offer("嘻嘻嘻");
System.out.println(qu);//[哈哈哈, 嘻嘻嘻]
// 3.获取队列头元素的方法
String s1 = qu.peek(); // -- 只是查看访问
System.out.println("队列头: " + s1);
System.out.println("队列: " + qu);
s1 = qu.poll(); // -- 获取队列头元素,并将元素从队列中移除
System.out.println("队列头2: " + s1);//哈哈哈
System.out.println("队列2: " + qu);//[嘻嘻嘻]
遍历
forEach
System.out.println(qu.poll())
Deque双端队列
拥有队列相关的所有方法 offer peek poll
offerFirst、offerLast:从队列头和尾加元素
pollFirst()、pollLast():从队列头和尾取元素
// 1.创建一个双端队列的方法
Deque<String> dq = new LinkedList<>();
// 2.拥有队列相关的所有方法 offer peek poll
dq.offer("哈哈哈");
dq.offer("嘻嘻嘻");
// 3.可以从队列头和尾加元素
dq.offerFirst("hahaha");
dq.offerLast("heihei"); // 等同于offer方法
System.out.println(dq);
// 4.可以从队列头和尾取元素
String s1 = dq.pollFirst(); // 等同于poll
System.out.println("队列头: " + s1);
System.out.println("队列: " + dq);
s1 = dq.pollLast();
System.out.println("队列尾: " + s1);
System.out.println("队列: " + dq);
LinkedList
Deque双端队列,当你使用它的 push压栈 和 pop 弹栈方法时, 他就变成了栈
// 链表栈
Deque<String> stack = new LinkedList<>();
stack.push("a");
stack.push("b");
stack.push("c");
System.out.println(stack);
String s = stack.pop();
System.out.println("栈顶元素: " + s);
System.out.println("栈: " + stack);
//[c, b, a]
//栈顶元素: c
//栈: [b, a]
//[h, i]
//stack2的栈顶: i
// 栈: 数组栈
Stack<String> stack2 = new Stack<>();
stack2.push("h");
stack2.push("i");
System.out.println(stack2);
String s2 = stack2.pop();
System.out.println("stack2的栈顶: " + s2);
二叉树优化(递归)
左 < 中 < 右
中序遍历
public class SortedTree<T> {
private class Node<T> {
private T data;
private Node left;
private Node right;
public Node(T data) {
this.data = data;
}
}
private Node<T> root; // 二叉树中的根节点
private void addToNode(Node node, T t) {
// 1.比较 node.data 和 t的大小
if (((Comparable) t).compareTo(node.data) < 0) {
// 加到node的左边
if (node.left == null) {
node.left = new Node<T>(t);
return;
}
addToNode(node.left, t);
} else if (((Comparable) t).compareTo(node.data) > 0) {
// 加到node的右边
if (node.right == null) {
node.right = new Node<T>(t);
return;
}
addToNode(node.right, t);
}
}
public void add(T t) {
// 1.判断根节点是否为空 -> 其实就是判断二叉树是否为空
if (root == null) {
root = new Node<T>(t);
return;
}
addToNode(root, t);
}
private void travelNode(Node node) {
if (node.left != null) {
travelNode(node.left);
}
System.out.println(node.data);
if (node.right != null) {
travelNode(node.right);
}
}
public void travel() {
travelNode(root);
}
//改泛型
/*public void add(T t) {
// 1.判断根节点是否为空 -> 其实就是判断二叉树是否为空
if (root == null) {
root = new Node<T>(t);
return;
}
Node node = root;
Node parentNode ;
// 2.判断 t 和 根节点.data 大小关系
while (true) {
parentNode = node;
if (((Comparable) t).compareTo(node.data) < 0) {
// 将t加入到node的左边
node = node.left;
if (node == null) {
parentNode.left = new Node<T>(t);
}
} else if (((Comparable) t).compareTo(node.data) > 0) {
// 将t加入到node的右边
node = node.right;
if (node == null) {
parentNode.right = new Node<T>(t);
}
}
}
}*/
public class Demo01Tree {
public static void main(String[] args) {
SortedTree<String> tree = new SortedTree<>();
tree.add("tom");
tree.add("hi");
tree.add("hehe");
tree.add("lucy");
tree.add("jack");
tree.travel();
}
Set(I)
API 和 Collection 的API 一样
- HashSet
- SortedSet(I)
HashSet
散列表/无序的, 不是随机!! 不允许重复元素
Set<String> set = new HashSet<>();
set.add("hello");
set.add("how");
set.add("are");
set.add("you");
// 不允许重复
set.add("you");
// [how, are, hello, you]
System.out.println(set);
add原理
详见图
remove移除
public static void main(String[] args){
Student s1 = new Student("张三", 12);
Student s2 = new Student("李四", 34);
Set<Student> set = new HashSet<>();
set.add(s1);
set.add(s2);
System.out.println(set.size());
// 属性值发生了改变
s1.setAge(21);
// 移除的时候,重新计算位置,发现位置上找不到s1对象,不会移除
set.remove(s1);
System.out.println(set.size());
//2
//2
why重写hashCode和equals
Set<Student> set = new HashSet<>();
set.add(new Student("张三", 12));
set.add(new Student("李四", 34));
set.add(new Student("张三", 12));
set.add(new Student("李四", 34));
System.out.println(set);
System.out.println(set.size());
/**
* 1.Student没有重写equals和hashCode, 添加进4个元素
* 2.重写了equals方法, 但是没有重写hashCode, 添加进4个元素
* 3.重写了hashCode方法, 但是没有重写equals, 添加进4个元素
* 4.重写了equals和hashCode方法, 添加进2个元素
*/
- 结论: hashCode和equals要一起重写
- 注意: equals方法判断相同的两个对象, hashCode方法结果一定要一致
- equals判断不相同的两个对象, hashCode结果要尽量不一样
SortedSet(I)
TreeSet: Comparable Comparator
特点: 不允许重复, 和equals方法无关
取决于 compare 或者 compareTo 方法
public static void main(String[] args){
Set<String> set = new TreeSet<>();
set.add("tom");
set.add("jack");
set.add("zhangsan");
set.add("lisi");
set.add("lisi");
System.out.println(set);//[jack, lisi, tom, zhangsan]
}
public static void main(String[] args){
// 可以通过构造方法, 传入比较器
Set<String> set = new TreeSet<>(new Comparator<String>(){
@Override
public int compare(String o1, String o2){
return o1.length() - o2.length();
}
});
set.add("zhangsan");
set.add("tom");
set.add("jack");
set.add("lisi");
set.add("lisi");
System.out.println(set);//[tom, jack, zhangsan]
}
总结
- Comparable的已知实现类: Date String Integer…
- Object中 hashCode() 方法默认得到的是 对象的物理地址
- hashCode没有重写, 所有对象的哈希值都不一样
- 哈希值不一样, 定位到的set中的位置, 可能相同
Map(I)
Map集合是有Key和Value的,Collection集合是只有Value。
映射表 key->value, 通过key 获得value
Map中的key, 单独的一部分, 就是Set
格式: xx = xxx, xx:xxx
常用API
put(key, value):添加(返回null), 替换(返回value)(被替换掉的value)
remove(key):通过key, 删除key-value, 返回被删掉的value值
get(key):通过key, 获得value
public static void main(String[] args){
Map<Integer, String> map = new HashMap<>();
// 1.向map集合中添加元素 key-value
String s = map.put(3, "张三");
map.put(4, "张三");
map.put(1, "张三");
map.put(2, "李四");
System.out.println("put返回值: " + s); // null
System.out.println(map);// {1=张三, 2=李四, 3=张三, 4=张三} -> toString重写过了
// 2.从集合中移除元素 key-value, 返回移除掉的value
String s2 = map.remove(1);
System.out.println("remove返回值: " + s2);
System.out.println(map);//{2=李四, 3=张三, 4=张三}
// 3.将集合中的元素修改
String s3 = map.put(3, "王五");
System.out.println("put返回值: " + s3); // 张三
System.out.println(map);//{2=李四, 3=王五, 4=张三}
// 4.获得map集合中的元素 value, 不存在的key, 对应的null
String s4 = map.get(5);
System.out.println("get返回值: " + s4); // null
System.out.println(map);//{2=李四, 3=王五, 4=张三}
}
HashMap
HashMap: key无序, 并且不重复
HashSet 就是value一样的 HashMap
TreeMap
TreeMap: key排好序的
// 1.无参构造方法创建TreeMap, 没有指定比较器
Map<String, Integer> map = new TreeMap<>();
map.put("lucy", 23);
map.put("tom", 18);
map.put("jack", 20);
map.put("zhangsan", 16);
System.out.println(map);//{jack=20, lucy=23, tom=18, zhangsan=16}
// 2.有参构造方法创建TreeMap, 传入比较器对象
Map<String, Integer> map = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
map.put("lucy", 23);
map.put("tom", 18);
// 添加jack的时候, 比较器结果认定jack和lucy相等的, 所以将原来的value值替换
map.put("jack", 20);
map.put("zhangsan", 16);
System.out.println(map);//{tom=18, lucy=20, zhangsan=16}
LinkedHashMap
LinkedHashMap: key有序的
public static void main(String[] args) {
Map<String, String> map = new LinkedHashMap<>();
map.put("lucy", "有点傻");
map.put("jack", "有点呆");
map.put("tom", "有点蠢");
map.put("rose", "有点萌");
// 结果: 按照插入顺序排列, 有序的
System.out.println(map);//{lucy=有点傻, jack=有点呆, tom=有点蠢, rose=有点萌}
}
迭代方式
keySet()
遍历key
// 遍历方式1: 将map中的key的部分, 单独取出, 成为set, 遍历这个set
public class Demo02HashMap{
public static void main(String[] args){
Map<String, String> map = new HashMap<>();
map.put("张三","12334345");
map.put("李四","3245345");
map.put("王五","567890");
map.put("赵六","98765432");
// 遍历方式1: 将map中的key的部分, 单独取出, 成为set, 遍历这个set
Set<String> set = map.keySet();
// 遍历key
for (String key:set) {
// 通过key获得value
String value = map.get(key);
System.out.println(key + " = " + value);
}
}
entrySet()
Set<Entry<K,V>> entrySet(): key-value封装成Entry
// 遍历方式2: 键值对封装成一个整体-Entry, Set<Entry>
public class Demo03HashMap {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("张三","12334345");
map.put("李四","3245345");
map.put("王五","567890");
map.put("赵六","98765432");
// 遍历方式2: 键值对封装成一个整体-Entry, Set<Entry>
Set<Entry<String, String>> set = map.entrySet();
for (Entry<String, String> en:set) {
// 获得key
String key = en.getKey();
String value = en.getValue();
System.out.println(key + " = " + value);
}
}
}
values()
Collection values(): 遍历value
// 遍历方式3: 将map中的value部分获取出来, 成为List, 遍历这个List
// 弊端: 就只能遍历值, 不能遍历键, 因为map不能反向映射
public class Demo04HashMap {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("张三","12334345");
map.put("李四","3245345");
map.put("王五","567890");
map.put("赵六","98765432");
// 遍历方式3: 将map中的value部分获取出来, 成为List, 遍历这个List
// 弊端: 就只能遍历值, 不能遍历键, 因为map不能反向映射
Collection<String> values = map.values();
for (String value : values) {
System.out.println(value);
}
}
Hashtable和区别
-
Hashtable 和 HashMap 有什么区别?
存储内容-null, 线程安全, 效率, 底层实现结构 -
LinkedHashMap 和 HashMap 有什么区别?
底层实现结构 -
ConcurrentHashMap 和 Hashtable 和 HashMap有什么区别
底层实现结构
应用——统计个数
案例: 手动输入字符串 ewretyuyjytrerthy
统计这个字符串中每个字符出现的次数
e:3, w:1, r:3, t:3…
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
String str = console.nextLine();
Map<Character, Integer> map = new HashMap<>();
// 1.将字符串转换成字符数组
char[] chars = str.toCharArray();
// 2.遍历数组, 进行统计
for (char c : chars) {
// 判断c是不是第一次出现
Integer ori = map.get(c);
if (ori == null) {
ori = 0;
}
map.put(c, ori + 1);
}
System.out.println(map);