Java刷題時常用的標准庫數據結構和相應操作


一、線性表(廣義的數組)

在算法題中,我們一般使用到的線性表一般有兩種,且它們的優缺點如下:

  • 數組
    • 優點:可以使用[]運算符進行隨機讀寫
    • 缺點:數組大小固定,不能動態添加數據
  • 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];
}

打印展示:

image-20220303213535341

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()

參考資料:https://codingdict.com/questions/3373

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()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM