鴻蒙HarmonyOS實戰-ArkTS語言基礎類庫(容器類庫)

蜀道山QAQ發表於2024-06-05

🚀前言

容器類庫是指一組用於儲存和管理資料的資料結構和演算法。它們提供了各種不同型別的容器,如陣列、連結串列、樹、圖等,以及相關的操作和功能,如查詢、插入、刪除、排序等。

容器類庫還可以包含其他資料結構和演算法,如堆、樹、圖等,以及相關的操作和功能,如排序、查詢、遍歷等。它們可以用於解決各種不同的問題和場景,提供了方便、高效和可靠的資料管理和操作功能。

🚀一、容器類庫

🔎1.線性容器

🦋2.1 ArrayList

ArrayList可以儲存任意型別的物件,包括基本資料型別的包裝類。

與普通陣列相比,ArrayList的優勢在於可以動態增加和縮減元素的數量,而不需要手動調整陣列的大小。當需要新增或刪除元素時,ArrayList會根據需要自動擴容或縮減。ArrayList依據泛型定義,要求儲存位置是一片連續的記憶體空間,初始容量大小為10,並支援動態擴容,每次擴容大小為原始容量的1.5倍。

ArrayList提供了一系列方法用於操作集合中的元素,包括新增、刪除、修改和查詢等操作。可以使用get方法獲取指定位置的元素,使用add方法在指定位置新增元素,使用remove方法刪除指定位置的元素等等。

需要注意的是,ArrayList是非執行緒安全的,如果多個執行緒同時訪問同一個ArrayList物件,可能會引發併發訪問異常。如果需要在多執行緒環境下使用ArrayList,可以使用Collections類提供的synchronizedList方法將ArrayList轉換為執行緒安全的List。

更多鴻蒙最新技術知識點,請關注作者部落格:https://t.doruo.cn/14DjR1rEY

🦋2.2 Vector

Vector和ArrayList在實現上確實相似,都是透過陣列來儲存元素,但有一些細微的差別。

  1. 執行緒安全性:Vector是執行緒安全的,而ArrayList不是。因為Vector的方法都是同步的,可以在多執行緒環境下安全使用,但這也導致了Vector在效能上比ArrayList稍慢。

  2. 動態擴容:Vector的擴容機制是每次擴容容量為原始容量的2倍,而ArrayList是每次擴容容量為原始容量的1.5倍。

  3. 初始容量:Vector的初始容量大小為10,而ArrayList的初始容量為0。

  4. 介面:Vector相比ArrayList提供了更多的運算元組的介面,如insertElementAt、removeElementAt等,這些介面可以更方便地在陣列中插入、刪除元素。

Vector在某些特定的場景下可能更適合使用,比如在多執行緒環境下或者需要頻繁進行插入、刪除元素的情況下。而ArrayList在單執行緒環境下效能更好,適合大部分場景。

API version 9開始,該介面不再維護,推薦使用ArrayList。

🦋2.3 List

List可以用來構造單向連結串列物件,每個節點包含一個資料元素和一個指向下一個節點的引用。連結串列中的節點在記憶體中可以是不連續的,因此可以靈活地進行插入和刪除操作。

當需要頻繁進行插入和刪除操作時,使用List可以更高效地操作連結串列。因為插入和刪除操作只需要改變節點的引用,而不需要移動其他節點。相比之下,如果使用陣列或者其他連續記憶體的資料結構,插入和刪除操作可能需要移動大量的元素,效率較低。

🦋2.4 LinkedList

LinkedList是一種雙向連結串列,每個節點除了儲存資料外,還有兩個指標分別指向前一個節點和後一個節點。這樣的結構使得LinkedList可以快速地在頭尾進行插入和刪除操作,因為只需要改變相鄰節點的指標即可,不需要像陣列一樣進行資料的搬移。

另外,LinkedList的記憶體儲存位置可以是不連續的,這是因為每個節點只需要儲存指向前後節點的指標,並不需要連續儲存資料,所以在記憶體中的儲存位置可以是不連續的。

相比之下,List介面代表一種有序的資料集合,可以包含重複的元素,但是沒有提供快速的插入和刪除操作。List的具體實現類,如ArrayList,底層實現是陣列,而不是連結串列。雖然ArrayList在查詢操作上效率更高,因為可以根據索引快速訪問元素,但是插入和刪除操作需要搬移後續元素,效率較低。

如果需要頻繁地進行插入和刪除操作,尤其是在列表的頭尾進行操作,推薦使用LinkedList。而如果需要頻繁地進行查詢操作,或者需要透過索引直接訪問元素,推薦使用ArrayList。

🦋2.5 Deque

Deque是一種雙端佇列,它繼承自Queue介面,提供了一些額外的方法來支援在隊頭和隊尾進行新增和刪除元素的操作。

Deque介面的主要方法包括:

  • addFirst(E e):在隊頭插入指定元素。
  • addLast(E e):在隊尾插入指定元素。
  • removeFirst():移除並返回隊頭元素。
  • removeLast():移除並返回隊尾元素。
  • getFirst():返回隊頭元素。
  • getLast():返回隊尾元素。

Deque的實現類有ArrayDeque和LinkedList。ArrayDeque是基於陣列實現的,而LinkedList是基於連結串列實現的。

🦋2.6 Queue

Queue是一種具有先進先出(FIFO)特性的資料結構。它的實現可以透過陣列或連結串列來完成。

在陣列實現的Queue中,需要定義一個陣列來儲存元素,以及兩個指標front和rear來分別指向隊頭和隊尾。當元素入隊時,rear指標向後移動,並將元素新增到rear指標所指向的位置;當元素出隊時,front指標向後移動,將front指標所指向的元素刪除。

在連結串列實現的Queue中,每個節點都有一個指標指向下一個節點,隊頭則是連結串列的第一個節點,隊尾是連結串列的最後一個節點。元素入隊時,將元素新增到連結串列的末尾;元素出隊時,刪除連結串列的第一個節點。

Queue的特性使得它在很多場景下都很有用,比如處理任務排程、訊息佇列、快取等。實際上,很多程式語言都提供了Queue的實現,可以直接使用。

更多鴻蒙最新技術知識點,請關注作者部落格:https://t.doruo.cn/14DjR1rEY

🦋2.7 Stack

Stack類可以用來建立棧物件,該棧物件按照先進後出的規則儲存元素。

Stack類基於泛型定義,要求儲存位置需要是一片連續的記憶體空間,初始容量大小為8,並且支援動態擴容。每次擴容大小是原始容量的1.5倍。Stack類底層基於陣列實現,入棧和出棧操作都是在陣列的一端進行。

Stack類和Queue類相比,Queue類基於迴圈佇列實現,只能在一端進行刪除操作,而在另一端進行插入操作。而Stack類則只在一端進行操作。

一般情況下,如果滿足先進後出的場景,可以使用Stack類。

🦋2.8 線性容器的使用

// ArrayList
import ArrayList from '@ohos.util.ArrayList'; // 匯入ArrayList模組

let arrayList = new ArrayList();
arrayList.add('a');
arrayList.add(1); // 增加元素
console.info(`result: ${arrayList[0]}`); // 訪問元素
arrayList[0] = 'one'; // 修改元素
console.info(`result: ${arrayList[0]}`);

// Vector
import Vector from '@ohos.util.Vector'; // 匯入Vector模組

let vector = new Vector();
vector.add('a');
let b1 = [1, 2, 3];
vector.add(b1);
vector.add(false); // 增加元素
console.info(`result: ${vector[0]}`); // 訪問元素
console.info(`result: ${vector.getFirstElement()}`); // 訪問元素

// Deque
import Deque from '@ohos.util.Deque'; // 匯入Deque模組

let deque = new Deque;
deque.insertFront('a');
deque.insertFront(1); // 增加元素
console.info(`result: ${deque[0]}`); // 訪問元素
deque[0] = 'one'; // 修改元素
console.info(`result: ${deque[0]}`);

// Stack
import Stack from '@ohos.util.Stack'; // 匯入Stack模組 

let stack = new Stack();
stack.push('a');
stack.push(1); // 增加元素
console.info(`result: ${stack[0]}`); // 訪問元素
stack.pop(); // 刪除棧頂元素並返回該刪除元素
console.info(`result: ${stack.length}`);

// List
import List from '@ohos.util.List'; // 匯入List模組

let list = new List;
list.add('a');
list.add(1);
let b2 = [1, 2, 3];
list.add(b2); // 增加元素
console.info(`result: ${list[0]}`); // 訪問元素
console.info(`result: ${list.get(0)}`); // 訪問元素

image

好像在預覽模式下,效果不盡人意

🔎2.非線性容器

🦋2.1 HashMap

HashMap是一個非常常用的集合類,用來儲存鍵值對。它透過key的hashCode值來確定key的儲存位置,從而實現快速查詢。由於HashMap的實現採用了連結串列來解決衝突問題,所以當存在多個key的hashCode相同時,它們會被放在同一個連結串列中。這也是為什麼HashMap可以儲存多個值對應同一個key的原因。

HashMap的初始容量為16,當容量不足時,會自動進行擴容,每次擴容容量會變為原來的兩倍。這樣可以減少擴容的次數,提高效能。

🦋2.2 HashSet

HashSet內部使用了HashMap作為其底層資料結構,將元素儲存在HashMap的key中,而HashMap的value則統一為一個固定的物件(稱為PRESENT)。HashSet中的元素實際上是HashMap的鍵值對中的key部分,而value部分無意義。

HashSet的存取速度很快,插入和刪除操作的時間複雜度均為O(1)。HashSet具有去重的功能,即當新增重複元素時只保留一個副本。HashSet允許儲存空值(null)。

HashSet的元素儲存是無序的,即元素的順序不固定。如果需要有序儲存元素,可以使用LinkedHashSet。HashSet適用於需要儲存不重複元素且對元素的順序沒有特殊要求的場景。

🦋2.3 TreeMap

TreeMap是一種用於儲存鍵值對的有序對映的資料結構。並且根據鍵的自然順序或按指定的比較器對鍵進行排序。TreeMap基於紅黑樹實現,因此它的鍵值對是有序的。與HashMap不同,TreeMap的鍵是唯一的,並且不能為null,而值可以為null。

TreeMap提供了一些常用的方法,例如put(key, value)用於將鍵值對新增到TreeMap中,get(key)用於根據鍵獲取對應的值,containsKey(key)用於檢查TreeMap中是否包含指定的鍵,remove(key)用於刪除指定鍵的鍵值對等。

由於TreeMap是有序的,它的鍵值對是按照鍵的自然順序或者按照指定的比較器進行排序的。這使得TreeMap非常適合用於根據鍵的排序來遍歷資料,或者獲取一段範圍內的資料。

🦋2.4 TreeSet

TreeSet可用來儲存一系列值的集合,儲存的元素中value是唯一的。它依據泛型定義,集合中的value值是有序的,底層是一棵二叉樹,可以透過樹的二叉查詢快速找到該value值,value的型別滿足ECMA標準中要求的型別。TreeSet中的值是有序儲存的,底層基於紅黑樹實現,可以進行快速的插入和刪除。

TreeSet基於TreeMap實現,只對value物件進行處理。它可用於儲存一系列值的集合,元素中value唯一且有序。

與HashSet相比,HashSet中的資料無序存放,而TreeSet是有序存放。它們集合中的元素都不允許重複,但HashSet允許放入null值,而TreeSet不建議插入空值,可能會影響排序結果。

一般需要儲存有序集合的場景,可以使用TreeSet。

🦋2.5 LightWeightMap

LightWeightMap是一個用來儲存具有關聯關係的key-value鍵值對集合的資料結構。其中,每個key都是唯一的,且對應一個value值。LightWeightMap採用了更加輕量級的結構,並使用hash來標識唯一的key。在衝突發生時,採用線性探測法來解決。

集合中的key值的查詢過程依賴於hash值和二分查詢演算法。首先將所有的key的hash值儲存在一個陣列中,然後透過這些hash值來對映到其他陣列中的key值和value值。key的型別需要滿足ECMA標準中的要求。

🦋2.6 LightWeightSet

LightWeightSet是一種用來儲存一系列值的集合,其中儲存的元素的value值是唯一的。它採用泛型定義,並使用了輕量級的結構。初始預設容量大小為8,每次擴容大小為原始容量的2倍。
在LightWeightSet中,value值的查詢依賴於hash和二分查詢演算法。具體來說,它使用一個陣列儲存hash值,並將hash值對映到其他陣列中的value值中。這裡的value的型別需要滿足ECMA標準中的要求。

LightWeightSet底層使用hash實現了對唯一value的標識,並採用了線性探測法作為衝突策略。它的查詢策略基於二分查詢法。

與HashSet相比,LightWeightSet佔用的記憶體更小。因此,當需要存取某個集合或對某個集合進行去重時,推薦使用佔用記憶體更小的LightWeightSet。

更多鴻蒙最新技術知識點,請關注作者部落格:https://t.doruo.cn/14DjR1rEY

🦋2.7 PlainArray

PlainArray可以看作是一個輕量級的陣列,其特點是key值的型別為number,並且每個key對應一個value值。它適用於儲存具有關聯關係的鍵值對集合,其中key是唯一的。

由於PlainArray採用了更加輕量級的結構,所以對於查詢操作,它依賴於二分查詢演算法來找到對應key值的索引,然後再透過該索引對映到其他陣列中的value值。

透過使用PlainArray,我們可以高效地儲存和查詢鍵值對集合,尤其適用於大規模資料的情況下。它提供了一種輕量級的、基於陣列的儲存方式,既可以保持鍵值對的關聯關係,又可以提供高效的查詢操作。

PlainArray和LightWeightMap都是用來儲存鍵值對,且均採用輕量級結構,但PlainArray的key值型別只能為number型別。

🦋2.8 非線性容器的使用

// HashMap
import HashMap from '@ohos.util.HashMap'; // 匯入HashMap模組

let hashMap = new HashMap();
hashMap.set('a', 123);
hashMap.set(4, 123); // 增加元素
console.info(`result: ${hashMap.hasKey(4)}`); // 判斷是否含有某元素
console.info(`result: ${hashMap.get('a')}`); // 訪問元素

// TreeMap
import TreeMap from '@ohos.util.TreeMap'; // 匯入TreeMap模組

let treeMap = new TreeMap();
treeMap.set('a', 123);
treeMap.set('6', 356); // 增加元素
console.info(`result: ${treeMap.get('a')}`); // 訪問元素
console.info(`result: ${treeMap.getFirstKey()}`); // 訪問首元素
console.info(`result: ${treeMap.getLastKey()}`); // 訪問尾元素

// LightWeightMap
import LightWeightMap from '@ohos.util.LightWeightMap'; // 匯入LightWeightMap模組

let lightWeightMap = new LightWeightMap();
lightWeightMap.set('x', 123);
lightWeightMap.set('8', 356); // 增加元素
console.info(`result: ${lightWeightMap.get('a')}`); // 訪問元素
console.info(`result: ${lightWeightMap.get('x')}`); // 訪問元素
console.info(`result: ${lightWeightMap.getIndexOfKey('8')}`); // 訪問元素

// PlainArray
import PlainArray from '@ohos.util.PlainArray' // 匯入PlainArray模組

let plainArray = new PlainArray();
plainArray.add(1, 'sdd');
plainArray.add(2, 'sff'); // 增加元素
console.info(`result: ${plainArray.get(1)}`); // 訪問元素
console.info(`result: ${plainArray.getKeyAt(1)}`); // 訪問元素

image

好像在預覽模式下,效果不盡人意

🚀寫在最後

  • 如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
  • 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
  • 關注小編,同時可以期待後續文章ing🚀,不定期分享原創知識。
  • 更多鴻蒙最新技術知識點,請關注作者部落格:https://t.doruo.cn/14DjR1rEY

image

相關文章