Set
方法介绍
特点
List利用Set去重
总结
Queue
介绍
常用操作
总结
PriorityQueue
介绍
总结
Deque
介绍
Deque和Queue区别
基本使用
总结
Stack
介绍
Stack作用
总结
Set
方法介绍
- boolean add(E e) 添加元素
- boolean remove(Object o) 移除元素
- boolean contains(Object o) 是否包含元素
- int size() 元素个数
Set<String> set = new HashSet<>();
set.add("abc"); // true
set.add("xyz"); // true
set.size(); // 2
set.add("xyz"); // false
set.size(); // 2
set.contains("abc"); // true
set.remove("abc"); // true
set.size(); // 1
set.contains("abc"); // false
set.remove("test"); // false
set.size(); // 1
特点
Set用于存储不重复的元素集合:
- Set实际上相当于不存储Value的Map
- Set用于去除重复元素
- 放入Set的元素要正确实现equals()和hashCode()
Set不保证有序:
- HashSet是无序的
- TreeSet是有序的
- 实现了SortedSet接口的是有序Set
Set<String> set = new HashSetM<>();
set.add("apple");
set.add("banana");
set.add("orange");
for (String s : set) {
System.out.println(s);
}
// 无序的 banana, orange, apple
Set<String> set = new TreeSet<>();
set.add("banana");
set.add("apple");
set.add("orange");
for (String s : set) {
System.out.println(s);
}
// 有序的 apple, banana, orange
自定义排序算法:
Set<String> set = new TreeSet<>(new Comparator<String>(){
public int compare(String o1, String o2) {
// 倒序排序
return - o1.compareTo(o2);
}
});
set.add("banana");
set.add("apple");
set.add("orange");
for (String s : set) {
System.out.println(s);
}
// 倒序的 orange, banana, apple
List利用Set去重
List<String> list = Arrays.asList("pear", "apple", "banana", "apple");
// 转化为set去重
Set<String> set = new HashSet<>(list);
// 或转化为TreeSet去重并排序
// Set<String> set = new TreeSet<>(list);
// 再转化为List
List<String> list1 = new ArrayList<String>(set);
// 自定义排序算法
Set<String> set2 = new TreeSet<>(new Comparator<String>() {
public int compare(String o1, String o2) {
// 倒序
return - o1.compareTo(o2);
}
});
// 把list数据添加到set
set2.addAll(list);
// 再转化为List
List<String> list2 = new ArrayList<String>(set2);
总结
- Set用于存储不重复的元素集合
- 放入Set的元素与作为Map的Key要求相同:
- 正确实现equals()和hashCode()
- 利用Set可以去除重复元素
- 遍历SortedSet按照元素的排序顺序遍历,也可以自定义排序算法
Queue
介绍
Queue实现了一个先进先出(FIFO)的队列
- FIFO:First In First Out
- LinkedList实现了Queue接口
常用操作
- 获取队列长度:size()
- 添加元素倒队尾:boolean add(E e) / boolean offer(E e)
Queue<String> q = new LinkedList<>();
if (q.offer("abc")) {
// add ok
} else {
// add failed
}
- 获取队列头部元素并删除:E remove() / E poll()
Queue<String> q = new LinkedList<>();
if (q.isEmpty()) {
// cannot poll
} else {
String first = q.poll();
}
- 获取队列头部元素但不删除:E element() / E peek()
Queue<String> q = new LinkedList<>();
if (q.isEmpty()) {
// cannot peek
} else {
String first = q.peek();
}
- 当添加或获取元素失败时,以上提供的两种方法的区别:
总结
- Queue 实现一个先进先出(FIFO)的队列
- add / offer 将元素添加到队尾
- remove / poll 从队首获取元素并删除
- element / peek 从队首获取元素但不删除
- 避免把null添加到队列
PriorityQueue
介绍
PriorityQueue的出队顺序与元素的优先级有关,父类AbstractQueue实现了Queue:
- remove() / poll() / element() / peek() 总是取优先级最高的元素
- 默认情况下PriorityQueue中的元素要实现Comparable接口,并实现compareTo方法
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Repository o) {
// 按name排序
return name.compareTo(o.name);
}
}
public class Main {
public static void main(String[] arge) {
PriorityQueue<Person> queue = new PriorityQueue<>();
queue.offer(new Person("Lili", 18));
queue.offer(new Person("Aiice", 20))
System.out.println(queue.peek());
// Person{name='Alice', age=20}
// compareTo方法改为 return - name.compareTo(o.name); 降序排序
// 结果为Person{name='Lili', age=18}
}
}
- 也可以通过自定义排序算法来排序,这样就不用元素类实现接口了
public class Main {
public static void main(String[] arge) {
PriorityQueue<Person> queue = new PriorityQueue<>(new Comparator<Person>(){
@Override
public int compare(Person1 o1, Person1 o2) {
// 倒序
return - o1.name.compareTo(o2.name);
}
});
queue.offer(new Person("Lili", 18));
queue.offer(new Person("Aiice", 20))
System.out.println(queue.peek());
// 结果为Person{name='Lili', age=18}
}
}
总结
- PriorityQueue实现了一个优先队列
- 从队首获取元素时,总是获取优先级最高的元素
- 默认按元素比较的顺序排序(必须实现Comparable接口)
- 可以通过Comparator自定义排序算法(不用实现Comparable接口)
#####Deque
介绍
Deque实现一个双端队列(Double Ended Queue)继承自Queue:
- 既可以添加到队尾,也可以添加到队首
- 既可以从队首获取, 又可以从队尾获取
Deque和Queue区别
基本使用
- 为了和Queue方法相区分,使用Deque时总是使用xxxFist / xxxLast方法
Deque<String> deque = new LinkedList<>();
deque.offerLast("end");
deque.offerFirst("abc");
String last = deque.peekLast();
String first = deque.peekFirst();
- Deque的实现类:ArrayDeque, LinkedList
因为LinkedList既实现了List接口,又实现了Deque接口,因此使用时习惯用接口类型来接收:
Deque<String> deque = new LinkedList<>();
deque.offerLast("z");
List<String> list = new LinkedList<>();
list.add("abc");
如果使用LinkedList来引用自己,则无法看出其具体是用作List还是Deque
// 不要这样写
LinkedList<String> obj = new LinkedList<>();
obj.offerLast("z");
总结
- Deque 实现了一个双端队列(Double Ended Queue)
- 将元素添加到队尾 / 队首:addLast / offerLast / addFirst / offerFirst
- 从队首 / 队尾获取元素并删除:removeFirst / pollFirst / removeLast / pollLast
- 从队首 / 队尾获取元素但不删除:getFirst / peekFirst / getLast / peekLast
- 总是调用xxxFirst / xxxLast 以便与Queue的方法区分开
- 避免把null添加到队列
Stack
介绍
栈(Stack)是一种后进先出(LIFO)的数据结构
- LIFO:Last In First Out
- push(E e):把元素压栈
- pop(E e):把栈顶的元素“弹出”
用Deque可以实现Stack的功能:
- push(E e):addFirst(E e)
- pop():removeFirst()
- peek():peekFirst()
Stack的作用
- 方法(函数)的嵌套调用
- 嵌套调用过多会造成栈溢出StackOverflowError
- 将整数转换为十六进制表示的String:12500 -> 0x30d4
12500 / 16 = 781...4 把4压栈
781 / 16 = 48...d 把d压栈
48 / 16 = 3...0 把0压栈
3 / 16 = 0...3 把3压栈
// 依次从栈顶取出为 30d4
- 将中缀表达式编译为后缀表达式进行计算
/*
中缀表达式:1 + 2 * (9 - 5)
编译器编译后
后缀表达式:1 2 9 5 - * +
计算过程:
1 2 9 5 依次压栈
遇到-,把5和9弹出,并计算-5+9得到4,把4压栈
遇到*,把4和2弹出,并计算4*2得到8,把8压栈
遇到+,把8和1弹出,并计算8+1得到9,把9压栈
计算结束,弹出9得到最终结果
*/
总结
- 栈(Stack)是一种后进先出(LIFO)的数据结构
- 操作栈的元素的方法
- push(E e):压栈
- pop():出栈
- peek():取栈顶元素但不出栈
- Java使用Deque实现栈的功能,注意只调用push / pop / peek,避免调用Deque其他方法
- 不要使用遗留类Stack