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