一、線性表(廣義的數組)
在算法題中,我們一般使用到的線性表一般有兩種,且它們的優缺點如下:
- 數組
- 優點:可以使用
[]運算符進行隨機讀寫 - 缺點:數組大小固定,不能動態添加數據
- 優點:可以使用
- List對象
- 優點:可以動態添加數據
- 缺點:讀寫數據需要使用
get(int index)和set(int index, Object object),和數組相比比較麻煩
1. 數組
這里數組的主要用法和c++比較類似,這里主要寫一下一些特殊的操作以及Arrays工具類提供的一些方法。
一維數組的定義和初始化
① 直接指定固定大小:
int[] arr = new int[n];
則開辟的空間會填充上默認值:
- 數值類型填充
0 boolean類型填充false- 對象類型填充
null
② 定義時進行初始化
int[] arr = new int[]{1, 2, 3, 4, 5};
二維數組的定義和初始化
① 和一維數組一樣直接給定兩個維度的大小(行數和列數):
int[][] matrix = new int[m][n];
② 和c++類似,二維數組也可以像c++中的type** matrix一樣,先給第一個維度分配空間,然后再為第二個維度分配不同的空間,例如下面的代碼分配下三角矩陣:
int n = 5;
int[][] matrix = new int[n][];
for (int i = 0; i < n; i++) {
matrix[i] = new int[i + 1];
}
打印展示:
Arrays工具類的一些常用方法
在Java中原生數組實際上並不是完全的面向對象的,對於List對象希望進行某項操作只需要使用.+方法即可,但數組類型本身卻沒有帶有這些操作,因而Arrays工具類填補了這部分的空白。
① Arrays.fill()
Arrays.fill有兩個常見的使用:
Arrays.fill(int[] array, int value)Arrays.fill(int[] array, int start, int end, int val)
這個函數是用於填充數組的,第一個參數是數組,第二個參數是填充的值,而第二種用法規定了填充的起止下標:[start, end)。
② Arrays.sort()
排序函數,一般也有兩種參數填充方法:
Arrays.sort(int[] array)Arrays.sort(Object[] array, Comparator c)tips 只有對象數組才能使用這種方式
第一種方式是按照默認的方式進行排序,數字類型按從小到大排,字符串類型按字典序排,而第二種方式中填寫的第二個參數是用於改變默認的排序規則的,例如這里我希望從大到小排序():
Integer[] arr = new Integer[]{1, 2, 3, 4, 5};
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
// 或者使用下面的更加簡潔的lambda表達式
Arrays.sort(arr, (num1, num2) -> num2 - num1);
由於添加Comparator對象的這種方式第一個參數只能是對象數組,因此我這里不再使用int[]而是改為了使用Integer[]。
這里就會出現一個這樣的需求:如果我原來的類型是
int[],那么如何轉換為Integer[]呢?這里我們可以使用下面的代碼進行轉化(其他的例如boolean到Boolean也可以按照如下方式轉化):int[] arrOrigin = new int[]{1, 2, 3, 4, 5}; Integer[] arr = (Integer[]) Arrays.stream(arrOrigin).boxed().toArray();即將原數組轉為stream對象后調用boxed方法得到
Stream<Integer>,最后再調用Stream類中的toArray()成員方法即可從流重新轉為數組。而Integer[]想要轉為int[]則需要調用Stream類的mapToInt(Integer::intValue).toArray()。
③ Arrays.toString(int[] array)
這個方法可以得到數組完整的內容,而如果直接使用arr.toString()只會得到對象的地址等無用信息。
④ Arrays.asList(int[] array)
將數組轉為List對象:
Integer[] arr = new Integer[]{1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(arr);
此外這個函數還可以分散填寫各個List對象初始元素的值:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
⑤ 反轉數組
這里可以使用工具類反轉的數組也僅限是對象數組(非對象數組可能只能手寫反轉算法了),參考代碼如下:
String[] strArr = new String[]{"e", "d", "c", "b", "a"};
Collections.reverse(Arrays.asList(strArr));
輸出結果:
[a, b, c, d, e]
另外還有一些例如Arrays.copyOf等方法不太常用,這里不再詳細介紹。
2. List接口容器
對象的構建
實現類一般使用ArrayList(此外還有LinkedList,但不常用),構造對象方式如下:
List<Integer> list = new ArrayList<>();
讀寫和插入刪除數據
讀:E get(int index)
寫:E set(int index, E element)
插入:boolean add(E e)和void add(int index, E element)
刪除:boolean remove(Object o)和E remove(int index)
排序
使用List的接口方法sort(Comparator c)(數字從大到小排):
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.sort((num1, num2) -> num2 - num1);
輸出:
[5, 4, 3, 2, 1]
或者也可以使用Collections.sort(List l, Comparator c),可以達到相同的效果。
反轉數組
// Collections工具類靜態方法:Collections.reverse(List list)
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Collections.reverse(list);
List轉為數組
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Integer[] arr = (Integer[]) list.toArray();
二、字符串
以下api如果沒有標注則默認為String類成員方法。
| 操作 | api | 說明 |
|---|---|---|
| 獲取長度 | int length() |
|
| 獲取下標對應字符 | char charAt(int index) |
|
| 轉換為字符數組 | char[] toCharArray() |
|
| 取子串 | String substring(int beginIdx, int endIdx) |
其中endIdx是可選的 |
| 轉為int等數字類型 | 靜態方法 Integer.parseInt(String str) |
這是int類型的,其他類型以此類推 |
| 數值類型轉為字符串 | 靜態方法 String.valueOf(T val) |
這里的T可以是int、double等類型 |
| 按分隔符切分字符串 | String[] split(String regex) |
填入的是正則表達式 |
| 反轉字符串 | StringBuilder成員方法 string reverse() |
需要借助StringBuilder |
這些容器類基本都會包含有獲取元素數量(
size())和判斷是否為空(empty()或isEmpty())等相同的方法,因此后面的api表格只列出該類特有的操作。
三、Map和Set
1. Map
Map這里一般使用的實現為HashMap,少數需要按照鍵進行排序時使用到TreeMap,構造對象如下:
Map<String, String> map = new HashMap<>();
常用操作和api:
| 操作 | api |
|---|---|
| 讀 | V get(Object key) |
| 寫 | V put(K key, V value) |
| 是否包含key | boolean containsKey(Object key) |
| 是否包含value | boolean containsValue(Object value) |
遍歷Map:
// 1. 使用forEach + lambda表達式(推薦)
map.forEach((key, value)-> {
...
});
// 2. 使用for結合keySet()
for (String key : map.keySet()) {
String value = map.get(key);
...
}
2. Set
和Map類似,這里Set的實現一般也選擇HashSet,少數需要按照鍵進行排序時使用到TreeSet,構造對象如下:
Set<String> set = new HashSet<>();
常用操作和api:
| 操作 | api |
|---|---|
| 插入元素 | boolean add(E e) |
| 刪除元素 | boolean remove(Object o) |
| 是否包含元素 | boolean contains(Object o) |
同理,set也可以使用forEach+lambda以及增強for兩種寫法遍歷元素。
四、棧Stack和隊列Queue
1. 棧Stack
構造對象:
Stack<String> stack = new Stack<>();
常用操作和api:
| 操作 | api |
|---|---|
| 壓棧 | E push(E item) |
| 彈棧 | E pop() |
| 查看棧頂元素 | E peek() |
2. 隊列Queue
Queue是一個接口,一般實現類取ArrayDeque。構造對象代碼如下:
Queue<String> queue = new ArrayDeque<>();
常用操作和api:
| 操作 | api |
|---|---|
| 入隊 | boolean offer(E e) |
| 出隊 | E poll() |
| 查看隊首 | E peek() |
五、優先隊列
構造對象:
PriorityQueue<Integer> heap = new PriorityQueue<>();
使用無參數構造函數時得到的是小頂堆,如果我們希望得到大頂堆則需要填入一個Comparator參數,如下為構造int類型大頂堆的方式:
PriorityQueue<Integer> heap = new PriorityQueue<>((o1, o2) -> o2 - o1);
其中填入的lambda表達式為新建Comparator匿名內部類的語法糖。
常用操作和api:
| 操作 | api |
|---|---|
| 入隊 | boolean offer(E e) |
| 出隊 | boolean poll(E e) |
| 查看隊首(堆頂) | E peek() |
