Java進階篇--數據結構

目錄

一.數組(Array):

1.1? 特點:

1.2? 基本操作:

1.3? 使用數組的好處包括:

1.4? 數組也有一些限制:

二.集合框架(Collections Framework):

2.1? 列表(List):

2.1.1? 數組列表(ArrayList):

擴展知識:

方法:

ArrayList的遍歷方式

ArrayList使用泛型

Arrays工具類

2.1.2? 鏈表(LinkedList):

常用方法:

2.1.3? 使用選擇:

2.1.4??示例代碼:

2.2? 集(Set):

2.2.1? 哈希集(HashSet):

基本類型對應的包裝類表如下:

HashSet的常用方法包括:

2.2.2? 樹集(TreeSet):

TreeSet的常用方法包括:

2.2.3? 使用選擇:

2.2.4??示例代碼:

2.3? 映射(Map):

2.3.1? 哈希映射(HashMap):

2.3.2? 樹映射(TreeMap):

2.3.3??使用選擇

2.3.4??示例代碼

三.棧(Stack)和隊列(Queue):

3.1方法

3.2示例代碼

四.樹(Tree):

4.1? 二叉樹(Binary Tree):

4.2二叉搜索樹(Binary Search Tree):

4.3??操作方法

4.4??樹的遍歷

4.4.1樹的遍歷包括兩種主要方式:

4.4.2? 樹的兩種基本遍歷方式:

4.5? 示例代碼

五.圖(Graph):

六.堆(Heap):

七.鏈表(LinkedList):

八.MAP:


Java 提供了多種數據結構來有效地組織和處理數據。以下是一些常見的 Java 數據結構:

一.數組(Array):

數組(Array)是一種線性數據結構,用于存儲固定大小的相同類型元素的連續序列,可以通過索引快速訪問和修改元素。。在 Java 中,數組可以包含基本類型(如 int、double、char 等)或引用類型(如對象、字符串等)的元素。

1.1? 特點:

  1. 元素類型必須相同,即數組是同一類型的項的集合。
  2. 長度固定,在創建數組時需要指定大小,后續無法改變。
  3. 內存中分配連續的空間,元素之間存儲緊密,通過索引快速訪問和修改元素。

1.2? 基本操作:

  • 初始化:創建一個數組,并為其賦初值。

  • 遍歷:使用循環遍歷數組中的每個元素。

  • 打印:將數組中的元素依次輸出。

  • 最大值:遍歷數組,通過比較找到數組中的最大值。

  • 最大值下標:遍歷數組,記錄當前最大值的下標。

  • 使用增強for循環(foreach):對于數組中的每個元素,可以使用增強for循環進行遍歷并執行相應的操作。
  • 復制數組有三種方法:
  1. 遍歷原數組,逐個復制到新數組。
  2. 使用System.arraycopy()方法進行數組復制。
  3. 使用數組的clone()方法復制數組。
  • 線性查找::從數組的第一個元素開始逐個比較,直到找到目標元素或遍歷完整個數組。時間復雜度為O(n),其中n為數組長度。
  • 二分查找:要求在已排序的數組中進行查找。首先確定數組的中間元素,將目標值與中間元素進行比較,若相等則返回該位置,若小于中間元素,則在左半部分繼續查找,若大于中間元素,則在右半部分繼續查找。重復以上步驟,直到找到目標值或查找范圍為空。時間復雜度為O(logn),其中n為數組長度。
  • 選擇排序:每次遍歷找到當前范圍內的最小(或最大)元素,并將其放置在已排序的部分的末尾。通過不斷選擇最小(或最大)的元素,逐步完成整個數組的排序。注意,選擇排序的時間復雜度為O(n^2),其中n為數組的長度。雖然簡單易實現,但對于較大規模的數據可能效率較低。

以下的Java代碼示例,包含數組的初始化、遍歷、打印、最大值、最大值下標、使用增強for循環遍歷、復制數組以及線性查找、二分查找和選擇排序算法的實現。

import java.util.Arrays;public class myClass {public static void main(String[] args) {// 初始化數組int[] arr = {5, 3, 9, 1, 7};// 遍歷數組for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();// 打印數組System.out.println(Arrays.toString(arr));// 最大值int max = arr[0];for (int i = 1; i < arr.length; i++) {if (arr[i] > max) {max = arr[i];}}System.out.println("最大值:" + max);// 最大值下標int maxIndex = 0;for (int i = 1; i < arr.length; i++) {if (arr[i] > arr[maxIndex]) {maxIndex = i;}}System.out.println("最大值下標:" + maxIndex);// 使用增強for循環遍歷for (int num : arr) {System.out.print(num + " ");}System.out.println();// 復制數組方法一(遍歷原數組,逐個復制到新數組)int[] copyArr1 = new int[arr.length];for (int i = 0; i < arr.length; i++) {copyArr1[i] = arr[i];}// 復制數組方法二(使用System.arraycopy()方法)int[] copyArr2 = new int[arr.length];System.arraycopy(arr, 0, copyArr2, 0, arr.length);// 復制數組方法三(使用數組的clone()方法)int[] copyArr3 = arr.clone();System.out.println("復制后的數組:" + Arrays.toString(copyArr3));// 線性查找int target = 9;int linearSearchIndex = -1;for (int i = 0; i < arr.length; i++) {if (arr[i] == target) {linearSearchIndex = i;break;}}System.out.println("線性查找:" + (linearSearchIndex != -1 ? linearSearchIndex : "未找到"));// 二分查找(前提是數組必須有序)Arrays.sort(arr); // 先排序int binarySearchIndex = Arrays.binarySearch(arr, target);System.out.println("二分查找:" + (binarySearchIndex >= 0 ? binarySearchIndex : "未找到"));// 選擇排序selectionSort(arr);System.out.println("選擇排序后的數組:" + Arrays.toString(arr));}// 選擇排序算法實現public static void selectionSort(int[] arr) {int n = arr.length;for (int i = 0; i < n - 1; i++) {int minIndex = i;for (int j = i + 1; j < n; j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}if (minIndex != i) {int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}}
}

運行結果:

5 3 9 1 7 
[5, 3, 9, 1, 7]
最大值:9
最大值下標:2
5 3 9 1 7 
復制后的數組:[5, 3, 9, 1, 7]
線性查找:2
二分查找:4
選擇排序后的數組:[1, 3, 5, 7, 9]

1.3? 使用數組的好處包括:

  1. 快速隨機訪問:由于元素在內存中連續存儲,所以可以通過索引快速定位和訪問元素。
  2. 內存效率:數組在創建時需要指定長度,適用于已知固定數量的元素存儲場景,不需要額外的指針或鏈接信息。
  3. 數組操作簡單:Java 提供了一些便利的方法和屬性,使得數組的操作更加簡單和高效。

1.4? 數組也有一些限制:

  • 長度固定:一旦創建,長度無法改變,需要事先確定好所需的元素個數。
  • 內存浪費:如果數組長度過大或未充分利用,會造成內存浪費。
  • 數據類型:數組只能存儲一種類型的數據;
  • 插入和刪除困難:在數組中插入或刪除元素可能需要移動其他元素,開銷較大。

二.集合框架(Collections Framework):

提供了一系列接口和類,用于存儲和操作對象的集合。常用的集合類包括:

2.1? 列表(List):

有序、可重復的集合,例如 ArrayList、LinkedList。

2.1.1? 數組列表(ArrayList):

  1. ArrayList是基于數組實現的動態數組,內部通過數組來存儲元素。
  2. 它可以自動擴容以適應元素的增加
  3. 它支持隨機訪問元素,即可以通過索引快速訪問指定位置的元素。
  4. 數組列表適用于頻繁讀取和隨機訪問元素的場景,因為它內部使用數組存儲,可以根據索引直接計算出元素的內存地址。
  5. ArrayList實現了List接口,繼承了AbstractList類,并且還實現了RandomAccess(隨機訪問)、Cloneable(克隆)和Serializable(可序列化)這些接口。
  6. 與Vector不同,ArrayList不是線程安全的。因此,在單線程環境下建議使用ArrayList,在多線程環境下可以選擇Vector或CopyOnWriteArrayList。

擴展知識:

Vector是Java中的一個舊的類,它與ArrayList具有相似的用法,但在性能和使用上存在一些差異。雖然Vector是線程安全的,但在大多數情況下,推薦使用更現代的替代方案。

一個常見的替代方案是使用Collections工具類提供的synchronizedList方法,該方法可以將ArrayList轉換為線程安全的List。以下是示例代碼:

List<String> lst = new ArrayList<>();
// 往lst中添加元素List<String> synList = Collections.synchronizedList(lst);

通過將原始的ArrayList通過synchronizedList方法包裝,我們可以獲得一個在并發環境下安全使用的List。

需要注意的是,在大多數情況下,如果不需要線程安全的特性,推薦使用ArrayList而不是Vector,因為ArrayList在性能上通常更優。只有在確實需要線程安全時,才會考慮使用Vector或通過Collections工具類獲得線程安全的List。

方法

Collection相關方法:

這些方法屬于Collection類的一部分,可以被List和Set等子類繼承并使用。以下是一些常見的Collection類方法:

  1. boolean add(E element):向集合中添加一個元素。
  2. boolean addAll(Collection<? extends E> collection):將一個集合中的所有元素添加到當前集合中。
  3. void clear():清空集合中的所有元素。
  4. boolean contains(Object object):判斷集合是否包含指定對象。
  5. boolean containsAll(Collection<?> collection):判斷集合是否包含給定集合中的所有元素。
  6. boolean isEmpty():判斷集合是否為空。
  7. Iterator<E> iterator():返回一個用于迭代集合元素的迭代器。
  8. boolean remove(Object object):從集合中移除指定的對象。
  9. boolean removeAll(Collection<?> collection):從集合中移除給定集合中的所有元素。
  10. boolean retainAll(Collection<?> collection):僅保留集合中在給定集合中出現的元素,移除其他元素。
  11. int size():返回集合中的元素個數。
  12. Object[] toArray():將集合轉化為數組。
  13. <T> T[] toArray(T[] array):將集合轉化為指定類型的數組。

List接口:

List是Collection接口的子接口,擁有Collection所有方法外,還有一些對索引操作的方法。

  • void add(int index, E element):在索引index處插入元素element。
  • boolean addAll(int index, Collection<? extends E> c):將集合c中的所有元素插入到索引index處。
  • E remove(int index):移除并返回索引index處的元素。
  • int indexOf(Object o):返回對象o在ArrayList中第一次出現的索引。
  • int lastIndexOf(Object o):返回對象o在ArrayList中最后一次出現的索引。
  • E set(int index, E element):將索引index處的元素替換為新的element對象,并返回被替換的舊元素。
  • E get(int index):返回索引index處的元素。
  • List<E> subList(int fromIndex, int toIndex):返回從索引fromIndex(包含)到索引toIndex(不包含)的子列表。
  • void sort(Comparator<? super E> c):根據指定的Comparator對ArrayList中的元素進行排序。
  • void replaceAll(UnaryOperator<E> operator):使用指定的計算規則operator重新設置ArrayList的所有元素。
  • ListIterator<E> listIterator():返回一個ListIterator對象,該接口繼承了Iterator接口,在Iterator接口基礎上增加了以下方法,允許向前迭代并添加元素。
  • bookean hasPrevious():返回迭代器關聯的集合是否還有上一個元素;
  • E previous();:返回迭代器上一個元素;
  • void add(E e);:在指定位置插入元素;

更多 API 方法可以查看:ArrayList

ArrayList的遍歷方式

  1. 使用for循環和索引:
    for (int i = 0; i < arrayList.size(); i++) {E element = arrayList.get(i);// 處理元素
    }
    
  2. 使用for-each循環:
    for (E element : arrayList) {// 處理元素
    }
    
  3. 使用迭代器(Iterator)進行遍歷:
    Iterator<E> iterator = arrayList.iterator();
    while (iterator.hasNext()) {E element = iterator.next();// 處理元素
    }
    

ArrayList<E>使用泛型

泛型數據類型,用于設置 objectName(對象名) 的數據類型,只能為引用數據類型

對于ArrayList的泛型使用,可以通過在定義ArrayList時指定泛型類型來確保集合中只能存儲指定類型的元素。例如:

ArrayList<String> stringList = new ArrayList<>();
stringList.add("Hello");
stringList.add("World");
// 只能添加String類型的元素String element = stringList.get(0);
System.out.println(element);  // 輸出: Hello

通過使用泛型,可以提供類型安全,并且在編譯期間就能夠捕獲類型不匹配的錯誤。?

Arrays工具類

Arrays工具類是Java提供的用于操作數組的工具類,以下是一些常用的方法:

  1. boolean equals(a, b):比較兩個數組是否相等。
  2. void fill(array, value):將指定的值填充到數組中的所有元素。
  3. void sort(array):對數組進行排序。
  4. int binarySearch(array, key):在已排序的數組中使用二分查找來查找指定的元素。
  5. void arraycopy(src, srcPos, dest, destPos, length):將源數組中的某個范圍的元素復制到目標數組的指定位置。

2.1.2? 鏈表(LinkedList):

  1. LinkedList是基于鏈表實現的雙向鏈表,內部通過節點(Node)來存儲元素并連接起來。
  2. 節點中包含了當前元素的值,以及指向前一個節點和后一個節點的引用。
  3. 鏈表支持快速插入和刪除操作,因為只需要修改節點的引用關系即可,不涉及移動其他元素。
  4. 鏈表適用于頻繁插入和刪除元素的場景,因為在鏈表中插入和刪除元素的開銷相對較小。
  5. 由于鏈表的存儲方式不同于數組,因此在訪問某個位置的元素時需要遍歷鏈表,因此隨機訪問的效率較低。

常用方法:

  • void addFirst(E element):在鏈表的開頭插入元素。
  • void addLast(E element):在鏈表的末尾插入元素。
  • E getFirst():獲取鏈表中的第一個元素。
  • E getLast():獲取鏈表中的最后一個元素。
  • E removeFirst():移除并返回鏈表中的第一個元素。
  • E removeLast():移除并返回鏈表中的最后一個元素。
  • boolean contains(Object element):判斷鏈表是否包含指定元素。
  • int size():返回鏈表中的元素個數。
  • void clear():清空鏈表中的所有元素。

更多 API 方法可以查看:LinkedList

2.1.3? 使用選擇:

根據具體需求,選擇ArrayList還是LinkedList有以下一些考慮因素:

  1. 如果需要頻繁讀取和隨機訪問元素,可以選擇ArrayList。
  2. 如果需要頻繁插入和刪除元素,尤其是在列表的中間位置,可以選擇LinkedList。
  3. 如果對內存空間的利用比較敏感,LinkedList可能會占用更多的內存,而ArrayList使用的內存通常較為緊湊。

總的來說,ArrayList適用于讀取和隨機訪問操作更多的場景,而LinkedList適用于插入和刪除操作更頻繁的場景。

2.1.4??示例代碼:

下面一個簡單的示例代碼,展示了如何使用ArrayList和LinkedList進行基本操作:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class ListExample {public static void main(String[] args) {// 使用ArrayListList<String> arrayList = new ArrayList<>();// 添加元素arrayList.add("Apple");arrayList.add("Banana");arrayList.add("Orange");// 獲取元素String firstElement = arrayList.get(0);System.out.println("ArrayList中第一個元素:" + firstElement);// 遍歷元素System.out.println("ArrayList的元素:");for (String element : arrayList) {System.out.println(element);}// 刪除元素arrayList.remove("Banana");// 使用LinkedListList<Integer> linkedList = new LinkedList<>();// 添加元素linkedList.add(10);linkedList.add(20);linkedList.add(30);// 獲取元素int lastElement = linkedList.get(linkedList.size() - 1);System.out.println("LinkedList中最后一個元素:" + lastElement);// 遍歷元素System.out.println("LinkedList的元素:");for (int element : linkedList) {System.out.println(element);}// 刪除元素linkedList.remove(0);}
}

運行結果:

ArrayList中第一個元素:Apple
ArrayList的元素:
Apple
Banana
Orange
LinkedList中最后一個元素:30
LinkedList的元素:
10
20
30

2.2? 集(Set):

集是一種無序的集合,不允許重復元素,例如 HashSet、TreeSet。

2.2.1? 哈希集(HashSet):

  1. HashSet是基于哈希表實現的集合,具有快速查找性能。
  2. 哈希集不保證元素的順序,且不允許重復元素。如果試圖插入重復元素,插入操作將被忽略。
  3. 它還繼承了Set接口和Collection接口的其他方法
  4. HashSet允許存儲null元素。
  5. 添加、刪除和查找元素的平均時間復雜度為O(1)

HashSet 中的元素實際上是對象,一些常見的基本類型可以使用它的包裝類。

基本類型對應的包裝類表如下:

基本類型引用類型
booleanBoolean
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter

HashSet的常用方法包括:

  1. boolean add(E element):向集合中添加指定元素,如果元素已經存在,則返回false。
  2. boolean remove(Object element):從集合中移除指定元素,如果元素存在并成功移除,則返回true。
  3. boolean contains(Object element):檢查集合中是否包含指定元素,如果包含則返回true。
  4. int size():返回集合中元素的數量。
  5. void clear():清空集合中的所有元素。?

更多 API 方法可以查看:HashSet?

2.2.2? 樹集(TreeSet):

  1. TreeSet是基于紅黑樹(自平衡二叉搜索樹)實現的有序集合。
  2. 樹集中的元素按照自然順序或自定義比較器進行排序,默認情況下按照元素的自然排序方式進行排序。
  3. 它還繼承了Set接口和Collection接口的其他方法
  4. 樹集不允許插入null元素。
  5. 插入、刪除和查找元素的時間復雜度為O(log N),其中N為樹集中的元素個數。

TreeSet的常用方法包括:

  1. boolean add(E element):向集合中添加指定元素,如果元素已經存在,則返回false。
  2. boolean remove(Object element):從集合中移除指定元素,如果元素存在并成功移除,則返回true。
  3. boolean contains(Object element):檢查集合中是否包含指定元素,如果包含則返回true。
  4. int size():返回集合中元素的數量。
  5. void clear():清空集合中的所有元素。
  6. E first():返回集合中的第一個(最小)元素。
  7. E last():返回集合中的最后一個(最大)元素。
  8. Iterator<E> iterator():返回在此集合上進行迭代的迭代器。

2.2.3? 使用選擇:

  1. 使用HashSet時,你可以快速添加、刪除和查找元素,并且元素的順序可能不同。
  2. 如果你希望元素有一定的順序,你可以使用TreeSet,它會根據元素的排序規則保持元素的有序性。

2.2.4??示例代碼:

下面一個簡單的示例代碼,展示了如何使用HashSet和TreeSet進行基本操作:

import java.util.HashSet;// 引入 HashSet 類
import java.util.TreeSet;// 引入 TreeSet 類public class myClass {public static void main(String[] args) {// 使用HashSetHashSet<String> hashSet = new HashSet<>();// 添加元素hashSet.add("Apple");hashSet.add("Banana");hashSet.add("Orange");hashSet.add("Grape");// 輸出集合中的元素System.out.println("HashSet:");for (String fruit : hashSet) {System.out.println(fruit);}// 檢查元素是否存在System.out.println("HashSet contains 'Apple': " + hashSet.contains("Apple")); // true// 刪除元素hashSet.remove("Orange");// 輸出修改后的集合System.out.println("HashSet after removal:");for (String fruit : hashSet) {System.out.println(fruit);}// 使用TreeSetTreeSet<Integer> treeSet = new TreeSet<>();// 添加元素treeSet.add(5);treeSet.add(10);treeSet.add(3);treeSet.add(8);// 輸出集合中的元素System.out.println("TreeSet:");for (int num : treeSet) {System.out.println(num);}// 獲取最小元素和最大元素System.out.println("Min element: " + treeSet.first()); // 3System.out.println("Max element: " + treeSet.last()); // 10}
}

運行結果:

HashSet:
Apple
Grape
Orange
Banana
HashSet contains 'Apple': true
HashSet after removal:
Apple
Grape
Banana
TreeSet:
3
5
8
10
Min element: 3
Max element: 10

2.3? 映射(Map):

由鍵值對組成的集合,每個鍵唯一,例如 HashMap、TreeMap。

2.3.1? 哈希映射(HashMap):

  1. 它是基于哈希表實現的映射結構。
  2. HashMap是一個散列表,它存儲的內容是鍵值對(key-value)映射。
  3. HashMap使用鍵的哈希碼來確定存儲位置,實現了 Map 接口,通過鍵快速查找值。
  4. 它具有較快的插入和查找操作,但不保證元素的順序。

常用方法:

  1. put(key, value): 將鍵值對插入到哈希映射中。
  2. get(key): 根據鍵獲取對應的值。
  3. containsKey(key): 檢查哈希映射中是否包含指定的鍵。
  4. remove(key): 移除哈希映射中指定鍵的鍵值對。
  5. size(): 返回哈希映射中鍵值對的數量。

更多 API 方法可以查看:HashMap

2.3.2? 樹映射(TreeMap):

  1. 它是基于紅黑樹實現的有序映射結構。
  2. TreeMap將鍵按照自然順序或通過自定義的比較器進行排序,并在內部維護一個有序的鍵值對集合。因此,可以根據鍵的順序快速檢索、遍歷和范圍查找元素。

常用方法:

  1. put(key, value): 將鍵值對插入到樹映射中。
  2. get(key): 根據鍵獲取對應的值。
  3. containsKey(key): 檢查樹映射中是否包含指定的鍵。
  4. remove(key): 移除樹映射中指定鍵的鍵值對。
  5. size(): 返回樹映射中鍵值對的數量。
  6. firstKey(): 返回樹映射中最小的鍵。
  7. lastKey(): 返回樹映射中最大的鍵。
  8. subMap(fromKey, toKey): 返回樹映射中鍵的一個子集,范圍從 fromKey(包括)到 toKey(不包括)。

除了上述方法,哈希映射和樹映射還提供了其他一些類似的方法,如獲取所有鍵的集合、清空映射等。具體的方法使用可以參考Java的官方文檔或相關教程。

2.3.3??使用選擇

這兩種映射都是非常常用的數據結構,在不同的場景下使用。

  • HashMap適用于需要快速查找和插入元素的情況,并且不關心元素的順序。
  • TreeMap適用于需要有序性的場景,可以按照鍵的順序進行操作和遍歷,在維護有序性的同時支持各種基本操作。

2.3.4??示例代碼

下面一個簡單的示例代碼,展示了如何使用HashMap和TreeMap進行基本操作:

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;public class myClass {public static void main(String[] args) {// 使用HashMapMap<String, Integer> hashMap = new HashMap<>();// 添加鍵值對到HashMaphashMap.put("Apple", 1);hashMap.put("Banana", 2);hashMap.put("Orange", 3);// 獲取指定鍵的值int appleValue = hashMap.get("Apple");System.out.println("Apple的值為:" + appleValue);// 檢查HashMap是否包含指定鍵boolean containsKey = hashMap.containsKey("Banana");System.out.println("HashMap是否包含Banana:" + containsKey);// 移除指定鍵的鍵值對hashMap.remove("Orange");// 遍歷HashMap的鍵值對for (String key : hashMap.keySet()) {int value = hashMap.get(key);System.out.println("鍵:" + key + ",值:" + value);}System.out.println("----------------------");// 使用TreeMapMap<String, Integer> treeMap = new TreeMap<>();// 添加鍵值對到TreeMaptreeMap.put("Apple", 1);treeMap.put("Banana", 2);treeMap.put("Orange", 3);// 獲取最小的鍵String firstKey = ((TreeMap<String, Integer>) treeMap).firstKey();System.out.println("最小的鍵:" + firstKey);// 獲取最大的鍵String lastKey = ((TreeMap<String, Integer>) treeMap).lastKey();System.out.println("最大的鍵:" + lastKey);// 遍歷TreeMap的鍵值對for (String key : treeMap.keySet()) {int value = treeMap.get(key);System.out.println("鍵:" + key + ",值:" + value);}}
}

運行結果:

Apple的值為:1
HashMap是否包含Banana:true
鍵:Apple,值:1
鍵:Banana,值:2
----------------------
最小的鍵:Apple
最大的鍵:Orange
鍵:Apple,值:1
鍵:Banana,值:2
鍵:Orange,值:3

三.棧(Stack)和隊列(Queue):

棧是一種后進先出(LIFO)的數據結構,常用操作有入棧和出棧;隊列是一種先進先出(FIFO)的數據結構,常用操作有入隊和出隊。Java 提供了 Stack 類和 Queue 接口,并有相關實現類如 LinkedList。

  • 棧(Stack):是一種后進先出(LIFO)的數據結構,只允許在棧頂進行插入(入棧)和刪除(出棧)操作。相當于把元素放在一個類似于豎起的桶中,每次插入和刪除只能在桶的頂部進行。
  • 隊列(Queue):是一種先進先出(FIFO)的數據結構,從隊尾插入元素(入隊),從隊頭刪除元素(出隊)。可以理解為排隊,先進來的人先出去。

在Java中,可以使用Stack類表示棧,它是Vector的子類。而Queue接口是Java集合框架的一部分,它定義了隊列的基本操作,如入隊、出隊、獲取隊頭元素等。Java提供了多個Queue接口的實現類,其中常用的是LinkedList,它既實現了List接口,又實現了Deque接口,可以作為隊列或雙端隊列使用。

3.1方法

Stack的常用方法包括:

  1. push(element):將元素壓入棧頂。
  2. pop():彈出并返回棧頂的元素。
  3. peek():返回棧頂的元素,但不會將其從棧中移除。
  4. isEmpty():判斷棧是否為空。
  5. size():返回棧中元素的個數。

Queue的常用方法包括:

  1. add(element):將元素添加到隊尾。
  2. offer(element):將元素添加到隊尾,并返回是否成功。
  3. remove():移除并返回隊頭的元素。
  4. poll():移除并返回隊頭的元素,如果隊列為空則返回null。
  5. peek():返回隊頭的元素,但不會將其從隊列中移除。
  6. element():返回隊頭的元素,如果隊列為空則拋出異常。
  7. isEmpty():判斷隊列是否為空。
  8. size():返回隊列中元素的個數。

3.2示例代碼

下面一個簡單的示例代碼,展示了如何使用Stack和Queue進行基本操作:

import java.util.Stack;
import java.util.LinkedList;
import java.util.Queue;public class myClass {public static void main(String[] args) {// 使用StackStack<Integer> stack = new Stack<>();// 入棧操作stack.push(1);stack.push(2);stack.push(3);// 出棧操作int poppedElement = stack.pop();System.out.println("出棧元素:" + poppedElement);// 獲取棧頂元素int topElement = stack.peek();System.out.println("棧頂元素:" + topElement);// 判斷棧是否為空boolean empty = stack.isEmpty();System.out.println("棧是否為空:" + empty);System.out.println("----------------------");// 使用QueueQueue<String> queue = new LinkedList<>();// 入隊操作queue.offer("Apple");queue.offer("Banana");queue.offer("Orange");// 出隊操作String polledElement = queue.poll();System.out.println("出隊元素:" + polledElement);// 獲取隊頭元素String peekedElement = queue.peek();System.out.println("隊頭元素:" + peekedElement);// 判斷隊列是否為空boolean emptyQueue = queue.isEmpty();System.out.println("隊列是否為空:" + emptyQueue);}
}

運行結果:

出棧元素:3
棧頂元素:2
棧是否為空:false
----------------------
出隊元素:Apple
隊頭元素:Banana
隊列是否為空:false

四.樹(Tree):

樹是一種非線性的數據結構,由節點和邊組成,用于表示具有層級關系的數據結構。常見的樹結構包括二叉樹、平衡樹、紅黑樹等。Java 提供了 TreeSet 和 TreeMap 來實現樹結構。

4.1? 二叉樹(Binary Tree):

是一種特殊的樹結構,每個節點最多有兩個子節點:左子節點和右子節點。一個節點可以沒有子節點,也可以只有一個子節點。

4.2二叉搜索樹(Binary Search Tree):

也稱為二叉查找樹或排序二叉樹,是一種特殊的二叉樹。它具有以下性質:

  1. 對于任意節點,其左子樹上的所有節點的值都小于該節點的值。
  2. 對于任意節點,其右子樹上的所有節點的值都大于該節點的值。
  3. 左子樹和右子樹都必須是二叉搜索樹。

由于二叉搜索樹的性質,我們可以利用它來高效地進行查找、插入和刪除操作。對于任意節點,其左子樹的節點值都小于該節點,因此在查找、插入或刪除時,可以通過比較節點的值,有選擇性地在左子樹或右子樹中進行操作,從而提高效率。

Java中可以使用TreeSet和TreeMap來實現二叉搜索樹。它們基于紅黑樹(Red-Black Tree)實現,紅黑樹是一種自平衡的二叉搜索樹,保持了良好的平衡性能。

  1. TreeSet是一個基于紅黑樹實現的有序集合,它存儲的元素按照自然順序或者指定的比較器進行排序,并且不允許出現重復元素。
  2. TreeMap是一個基于紅黑樹實現的有序映射,它存儲鍵值對,并按照鍵的自然順序或者指定的比較器進行排序。與TreeSet類似,TreeMap也不允許出現重復的鍵。

通過使用TreeSet和TreeMap,我們可以方便地操作二叉搜索樹的相關操作,如插入、刪除、查找等,并保持元素的有序性。

4.3??操作方法

  1. 創建樹IntTree(&T):創建1個空樹T。
  2. 銷毀樹DestroyTree(&T)
  3. 構造樹CreatTree(&T,deinition)
  4. 置空樹ClearTree(&T):將樹T置為空樹。
  5. 判空樹TreeEmpty(T)
  6. 求樹的深度TreeDepth(T)
  7. 獲得樹根Root(T)
  8. 獲取結點Value(T,cur_e,&e):將樹中結點cur_e存入e單元中。
  9. 數據賦值Assign(T,cur_e,value):將結點value,賦值于樹T的結點cur_e中。
  10. 獲得雙親Parent(T,cur_e):返回樹T中結點cur_e的雙親結點。
  11. 獲得最左孩子LeftChild(T,cur_e):返回樹T中結點cur_e的最左孩子。
  12. 獲得右兄弟RightSibling(T,cur_e):返回樹T中結點cur_e的右兄弟。
  13. 插入子樹InsertChild(&T,&p,i,c):將樹c插入到樹T中p指向結點的第i個子樹之前。
  14. 刪除子樹DeleteChild(&T,&p,i):刪除樹T中p指向結點的第i個子樹。
  15. 遍歷樹TraverseTree(T,visit())

4.4??樹的遍歷

4.4.1樹的遍歷包括兩種主要方式:

  1. 深度優先遍歷(DFS):

    1. 先序遍歷(Preorder):根節點 -> 左子樹 -> 右子樹
    2. 中序遍歷(Inorder):左子樹 -> 根節點 -> 右子樹
    3. 后序遍歷(Postorder):左子樹 -> 右子樹 -> 根節點
  2. 廣度優先遍歷(BFS): 從根節點開始,按層級順序逐層遍歷樹的節點,從左到右依次訪問每個節點。

無論是深度優先遍歷還是廣度優先遍歷,都有各自的應用場景。可以根據具體需求選擇適合的遍歷方式來處理樹中的節點。

4.4.2? 樹的兩種基本遍歷方式:

  • 先序遍歷(Preorder traversal):
    1. 訪問根節點。
    2. 遞歸地對左子樹進行先序遍歷。
    3. 遞歸地對右子樹進行先序遍歷。

先序遍歷的順序是先訪問根節點,然后按照從左到右的順序依次訪問左子樹和右子樹。

  • 中序遍歷(Inorder traversal):
    1. 遞歸地對左子樹進行中序遍歷。
    2. 訪問根節點。
    3. 遞歸地對右子樹進行中序遍歷。

中序遍歷的順序是先按照從左到右的順序遞歸訪問左子樹,然后訪問根節點,最后按照從左到右的順序遞歸訪問右子樹。

這兩種遍歷方法都是通過遞歸實現的,可以用來遍歷二叉樹或其他類型的樹結構。它們在不同的情況下有各自的應用,具體取決于問題的需求。

4.5? 示例代碼

下面一個簡單的示例代碼,展示了如何使用Binary Tree和Binary Search Tree進行基本操作:

// 定義二叉樹節點類
class TreeNode {int val;TreeNode left;TreeNode right;public TreeNode(int val) {this.val = val;this.left = null;this.right = null;}
}// 二叉樹類
class BinaryTree {TreeNode root;public BinaryTree() {root = null;}// 插入節點public void insert(int val) {root = insertNode(root, val);}private TreeNode insertNode(TreeNode node, int val) {if (node == null) {return new TreeNode(val);}// 如果值小于當前節點,則插入左子樹if (val < node.val) {node.left = insertNode(node.left, val);}// 如果值大于等于當前節點,則插入右子樹else {node.right = insertNode(node.right, val);}return node;}// 先序遍歷public void preOrderTraversal() {preOrder(root);}private void preOrder(TreeNode node) {if (node == null) {return;}System.out.print(node.val + " ");preOrder(node.left);preOrder(node.right);}
}// 二叉搜索樹類
class BinarySearchTree {TreeNode root;public BinarySearchTree() {root = null;}// 插入節點public void insert(int val) {root = insertNode(root, val);}private TreeNode insertNode(TreeNode node, int val) {if (node == null) {return new TreeNode(val);}// 如果值小于當前節點,則插入左子樹if (val < node.val) {node.left = insertNode(node.left, val);}// 如果值大于等于當前節點,則插入右子樹else {node.right = insertNode(node.right, val);}return node;}// 中序遍歷public void inOrderTraversal() {inOrder(root);}private void inOrder(TreeNode node) {if (node == null) {return;}inOrder(node.left);System.out.print(node.val + " ");inOrder(node.right);}
}// 測試代碼
public class myClass {public static void main(String[] args) {// 創建二叉樹,并插入節點BinaryTree binaryTree = new BinaryTree();binaryTree.insert(5);binaryTree.insert(3);binaryTree.insert(7);binaryTree.insert(2);binaryTree.insert(4);binaryTree.insert(6);binaryTree.insert(8);// 先序遍歷二叉樹System.out.print("二叉樹 -先序遍歷: ");binaryTree.preOrderTraversal();System.out.println();// 創建二叉搜索樹,并插入節點BinarySearchTree binarySearchTree = new BinarySearchTree();binarySearchTree.insert(5);binarySearchTree.insert(3);binarySearchTree.insert(7);binarySearchTree.insert(2);binarySearchTree.insert(4);binarySearchTree.insert(6);binarySearchTree.insert(8);// 中序遍歷二叉搜索樹System.out.print("二叉搜索樹 - 中序遍歷: ");binarySearchTree.inOrderTraversal();System.out.println();}
}

運行結果:

二叉樹 -先序遍歷: 5 3 2 4 7 6 8 
二叉搜索樹 - 中序遍歷: 2 3 4 5 6 7 8 

五.圖(Graph):

圖(Graph)是由節點(Vertex)和邊(Edge)組成的一種非線性數據結構,用于表示對象之間的關聯關系。可以將節點視為圖中的元素,并且節點可以與其他節點通過邊相連接。

在實際應用中,圖可用于解決各種問題,如社交網絡分析、路徑搜索、最短路徑算法等。在 Java 中,可以自行實現圖的數據結構和相關算法,或使用第三方庫(如JGraphT、Java Universal Network/Graph Framework等)來操作和處理圖結構。

  • 有向圖(Directed Graph):也稱為有向圖、定向圖或有向網絡。有向圖中的邊具有方向性,表示節點之間的單向關系。如果節點 A 到節點 B 之間存在一條有向邊,那么從節點 A 出發可以到達節點 B,但反過來不行。
  • 無向圖(Undirected Graph):也稱為無向圖、非定向圖或無向網絡。無向圖中的邊沒有方向,表示節點之間的雙向關系。如果節點 A 和節點 B 之間有一條邊相連,則可以從節點 A 到節點 B 或者從節點 B 到節點 A。

六.堆(Heap):

堆是一種特殊的樹形數據結構,滿足堆屬性。用于有效地找到最大值或最小值的數據結構。Java 提供了優先級隊列(PriorityQueue)來實現堆。

  • 最大堆(Max Heap):每個父節點的值都大于或等于其子節點的值。
  • 最小堆(Min Heap):每個父節點的值都小于或等于其子節點的值。

七.鏈表(LinkedList):

鏈表是一種線性數據結構,也叫動態數據結構,但是并不會按線性的順序存儲數據,由節點和指針組成,每個節點包含數據和指向下一個節點的指針。

鏈表可分為單向鏈表和雙向鏈表。

一個單向鏈表包含兩個值: 當前節點的值和一個指向下一個節點的鏈接。

一個雙向鏈表有三個整數值: 數值、向后的節點鏈接、向前的節點鏈接。

八.MAP

Map是一種用于存儲鍵值對的接口。它提供了一種將鍵映射到值的方式,可以通過鍵快速查找對應的值。在Map中,鍵是唯一的,每個鍵最多只能映射到一個值。常見的Map實現類包括HashMap、TreeMap、LinkedHashMap等。這些實現類提供了不同的性能特點和迭代順序,可以根據具體需求選擇適合的實現類。使用Map可以方便地進行數據檢索、插入、刪除和更新操作,非常適合處理需要快速查找的場景。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/41209.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/41209.shtml
英文地址,請注明出處:http://en.pswp.cn/news/41209.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

當你出差在外時,怎樣輕松訪問遠程訪問企業局域網象過河ERP系統?

文章目錄 概述1.查看象過河服務端端口2.內網穿透3. 異地公網連接4. 固定公網地址4.1 保留一個固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址連接 概述 ERP系統對于企業來說重要性不言而喻&#xff0c;不管是財務、生產、銷售還是采購&#xff0c;都需要用到ERP系統來協助。…

miniconda克隆arcpy

arcpy環境克隆 前言嘗試思考到此結束 前言 最近遇到了一些問題&#xff0c;需要用到arcpy來處理一些東西&#xff0c;但眾所周知&#xff0c;arcgis的arcpy是python 2.0的&#xff0c;我不是很喜歡&#xff1b;所以我安裝了arcgis pro 2.8&#xff0c;我發現這也是個坑&#x…

Git分布式版本控制系統

目錄 2、安裝git 2.1 初始環境 2.2 Yum安裝Git 2.3 編譯安裝 2.4 初次運行 Git 前的配置 2.5 初始化及獲取 Git 倉庫 2.6 Git命令常規操作 2.6.2 添加新文件 2.6.3 刪除git內的文件 2.6.4 重命名暫存區數據 2.6.5 查看歷史記錄 2.6.6 還原歷史數據 2.6.7 還原未來…

react使用antd的table組件,實現點擊彈窗顯示對應列的內容

特別提醒&#xff1a;不能在table的columns的render里面設置彈窗組件渲染&#xff0c;因為這會導致彈窗顯示的始終是最后一行的內容&#xff0c;因為這樣渲染的結果是每一行都會重新渲染一遍這個彈窗并且會給傳遞一個content的值&#xff0c;渲染到最后一行的時候&#xff0c;就…

Unity的TimeScale的影響范圍分析

大家好&#xff0c;我是阿趙。 這期來說一下Unity的TimeScale。 一、前言 Unity提供了Time這個類&#xff0c;來控制時間。其實我自己倒是很少使用這個Time&#xff0c;因為做網絡同步的游戲&#xff0c;一般是需要同步服務器時間&#xff0c;所以我比較多是在使用System.Date…

linux驅動 - 20230817

練習: 通過字符設備驅動分步注冊方式編寫LED燈的驅動&#xff0c;應用程序使用ioctl函數編寫硬件控制邏輯 頭文件 head.h #ifndef __HEAD_H__ #define __HEAD_H__ typedef struct{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned…

問道管理:機器人概念走勢活躍,新時達漲停,拓斯達、豐立智能等大漲

機器人概念17日盤中走勢活躍&#xff0c;到發稿&#xff0c;拓斯達大漲18%&#xff0c;昊志機電漲近16%&#xff0c;豐立智能漲超13%&#xff0c;步科股份、優德精細漲超10%&#xff0c;新時達漲停&#xff0c;天璣科技、兆龍互聯、中大力德漲逾9%。 消息面上&#xff0c;8月16…

HTTP 介紹

HTTP 介紹 HTTP 協議一般指 HTTP&#xff08;超文本傳輸協議&#xff09;。超文本傳輸協議&#xff08;英語&#xff1a;HyperText Transfer Protocol&#xff0c;縮寫&#xff1a;HTTP&#xff09;是一種用于分布式、協作式和超媒體信息系統的應用層協議&#xff0c;是因特網…

Java 計算兩個字符的相似度

在Java中&#xff0c;要計算兩個字符的相似度&#xff0c;可以借助一些字符串相似度算法。以下是幾種常見的字符串相似度算法&#xff1a; Levenshtein距離&#xff1a;也稱為編輯距離&#xff0c;用于計算兩個字符串之間的最小編輯操作次數&#xff08;插入、刪除、替換&…

解決ios隔空播放音頻到macos沒有聲音的問題

解決ios隔空播放音頻到macos沒有聲音的問題 一、檢查隔空播放支持設備和系統要求二、打開隔空播放接收器三、重置MAC控制中心進程END 一、檢查隔空播放支持設備和系統要求 Mac、iPhone、iPad 和 Apple Watch 上“連續互通”的系統要求 二、打開隔空播放接收器 ps;我設備是同一…

java 并發 簡單使用

文章目錄 概要代碼 概要 java 并發 簡單使用 代碼 public static final ExecutorService EXECUTOR_GENERAL new ThreadPoolExecutor(100, 1000,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000));int size 1000;List<UserService> userServices …

element+vue 表格行拖拽功能

解決方案 使用 sortable.js 步驟一&#xff1a; 安裝 npm install vuedraggable步驟二&#xff1a;引入 import Sortable from sortablejs;步驟三&#xff1a; el-table 添加row-key屬性&#xff0c;外層包一層 sortableDiv <div class"sortableDiv"> 拖…

分類預測 | MATLAB實現WOA-CNN-BiLSTM-Attention數據分類預測

分類預測 | MATLAB實現WOA-CNN-BiLSTM-Attention數據分類預測 目錄 分類預測 | MATLAB實現WOA-CNN-BiLSTM-Attention數據分類預測分類效果基本描述程序設計參考資料 分類效果 基本描述 1.MATLAB實現WOA-CNN-BiLSTM-Attention數據分類預測&#xff0c;運行環境Matlab2023b及以上…

Django圖書商城系統實戰開發-部署上線操作

Django圖書商城系統實戰開發-打包部署 技術背景掌握 當你需要在服務器上部署Web應用程序時&#xff0c;Nginx是一個強大且常用的選擇。Nginx是一個高性能的Web服務器和反向代理服務器&#xff0c;它可以處理大量的并發連接&#xff0c;并提供負載均衡、緩存、SSL等功能。下面…

seata 的部署和集成

文章目錄 seata的部署和集成一、部署Seata的tc-server1.下載2.解壓3.修改配置4.在nacos添加配置5.創建數據庫表6.啟動TC服務 二、微服務集成seata1.引入依賴2.修改配置文件 TODO三、TC服務的高可用和異地容災1.模擬異地容災的TC集群2.將事務組映射配置到nacos3.微服務讀取nacos…

中期國際:MT4數據挖掘與分析方法:以數據為導向,制定有效的交易策略

在金融市場中&#xff0c;制定有效的交易策略是成功交易的關鍵。而要制定一份可靠的交易策略&#xff0c;數據挖掘與分析方法是不可或缺的工具。本文將介紹如何以數據為導向&#xff0c;利用MT4進行數據挖掘與分析&#xff0c;從而制定有效的交易策略。 首先&#xff0c;我們需…

操作系統搭建相關知識

文章目錄 系統篇netstat命令systemctl命令Systemd系統資源分類&#xff08;12類&#xff09; 網絡篇ifconfig命令操作系統配置動態IP腳本dhcp服務的安裝與配置防火墻相關知識 操作系統常用配置文件 系統篇 netstat命令 netstat指路 systemctl命令 常用于重啟系統的每個服務…

注解@DependsOn

注解 DependsOn 1. 注解由來&#xff1a; DependsOn 注解是 Spring 框架提供的一種注解&#xff0c;用于指定 Bean 之間的依賴關系。通過在 Bean 上添加 DependsOn 注解&#xff0c;可以確保在初始化時先初始化指定的依賴 Bean&#xff0c;從而滿足對象之間的正確順序。 2. 注…

沒有使用springboot 單獨使用spring-boot-starter-logging

如果您不使用Spring Boot框架&#xff0c;但想單獨使用Spring Boot Starter Logging&#xff0c;您可以按照以下步驟進行&#xff1a; 1. 添加Maven依賴&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boo…

Kotlin手寫RxJava變換符

Kotlin手寫RxJava變換符 本文鏈接&#xff0c;點擊這里進入 1、核心點&#xff1a;中轉站存儲之前的數據 2、三行代碼實現RxJava 使用create、map、observer fun main() {// create構造出RxJavaCore存放&#xff0c;lambda執行完的結果create{"WCH"}.map{ // 擴展…