一、線性表(廣義的數組)
在算法題中,我們一般使用到的線性表一般有兩種,且它們的優缺點如下:
- 數組
- 優點:可以使用
[]
運算符進行隨機讀寫 - 缺點:數組大小固定,不能動態添加數據
- 優點:可以使用
- 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() |