查找 Java 數組中元素的索引
一、概述
在本教程中,我們將通過代碼示例討論使用 Java 的內置 API 和第三方庫查找數組元素索引的各種方法。這對於許多任務都很有用,包括搜索、排序和修改數組。
2. 使用for
循環
我們的第一種方法是查找數組中元素索引的最簡單方法之一。這是通過使用for
循環。
這個想法是遍歷輸入數組並在每次迭代中檢查元素。如果找到該元素,則返回當前索引。
否則,如果我們找不到數組末尾的元素,我們將返回一個固定的常量值。這個固定值可以是我們事先知道的任何東西。我們用它來表示在數組中找不到該元素。
這些固定常量值的示例有-1
、 Integer.MAX_VALUE
、 Integer.MIN_VALUE
等。
首先,讓我們使用這種方法創建一個簡單的方法:
int forLoop(int[] numbers, int target) {
for (int index = 0; index < numbers.length; index++) {
if (numbers[index] == target) {
return index;
}
}
return -1;
}
我們遍歷輸入numbers
數組,然後檢查每個元素。如果找到匹配項,我們將返回當前index
值。否則,我們返回-1,
表示找不到target
。
現在讓我們用一些示例輸入數據測試我們的forLoop()
方法:
@Test
void givenIntegerArray_whenUseForLoop_thenWillGetElementIndex() {
int[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(2, forLoop(numbers, 30));
}
在這裡,我們正在尋找值30
。 forLoop()
方法返回2
,即輸入數組中的位置。我們必須記住,在 Java 中數組的起始索引是零。
接下來,讓我們尋找一個不在輸入數組中的元素:
@Test
void givenIntegerArray_whenUseForLoop_thenWillGetElementMinusOneIndex() {
int[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(-1, forLoop(numbers, 100));
}
在這種情況下,我們嘗試搜索數字100.
但是,它不存在於我們的數組中。這就是我們的方法返回-1
的原因,表明未找到該元素。
3.使用List
indexOf()
對於下一個方法,我們將使用List
類中的indexOf()
方法:
static int listIndexOf(Integer[] numbers, int target) {
List<Integer> list = Arrays.asList(numbers);
return list.indexOf(target);
}
在我們的listIndexOf()
方法中,我們傳遞一個Integer
數組和一個目標值作為參數。在幕後,我們使用Arrays
實用程序類中的asList()
方法。此方法將對像數組轉換為相同對像類型的List
。值得注意的是, asList()
方法沒有任何原始類型的實現。
輸入數組轉換為列表後,我們使用indexOf()
方法查找目標元素的索引。如果目標元素不在列表中,則indexOf()
方法返回-1
。
現在,讓我們實施幾個測試用例。在第一個中,目標將在輸入數組中:
@Test
void givenIntegerArray_whenUseIndexOf_thenWillGetElementIndex() {
Integer[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(2, listIndexOf(numbers, 30));
}
當我們調用listIndexOf()
方法時,我們得到索引2
,即目標數字30.
在第二個測試用例中,目標元素不在輸入數組中:
@Test
void givenIntegerArray_whenUseIndexOf_thenWillGetElementMinusOneIndex() {
Integer[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(-1, listIndexOf(numbers, 100));
}
在這種情況下,我們得到了預期的結果-1
。
4. 使用rrays
binarySearch()
Arrays
實用程序類中的另一個有用方法是binarySearch()
方法。此方法執行二進制搜索算法。在使用此方法之前必須對輸入數組進行排序。我們可以使用binarySearch()
方法來查找排序數組中元素的索引。
讓我們使用binarySearch()
方法實現一些測試:
@Test
void givenIntegerArray_whenUseBinarySearch_thenWillGetElementIndex() {
int[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(2, Arrays.binarySearch(numbers, 30));
}
使用上述代碼中的binarySearch()
方法,如果找到目標元素,該方法將返回其索引號。在這種情況下,我們得到索引2
。
但是,如果未找到目標,該方法將返回一個負值。根據 Java 中binarySearch()
方法的官方 文檔,這個負值是使用插入點計算的。插入點是鍵在數組中的位置。它的值是第一個大於鍵的元素的索引,如果數組中的所有元素都小於鍵,則為arr.length
。當元素不在數組中時,索引等於(-(insertion point)-1)
。
讓我們對這個負值進行一些測試:
@Test
void givenIntegerArray_whenUseBinarySearch_thenWillGetUpperBoundMinusIndex() {
int[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(-6, Arrays.binarySearch(numbers, 100));
}
由於100
不在數組中,因此該方法返回負值。在這種情況下,返回值為-6
。這是因為數組中的所有元素都小於我們的target
。然後,插入點為5
(數組長度),結果索引為(-5-1)
,即-6
。
另一種情況是當目標元素值介於數組的上限值和下限值之間時:
@Test
void givenIntegerArray_whenUseBinarySearch_thenWillGetInArrayMinusIndex() {
int[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(-2, Arrays.binarySearch(numbers, 15));
}
在上面的測試用例中,由於 15 是 10 到 50 之間的值,這個數組的邊界值,我們得到索引值-2
。我們得到這個值是因為插入點是1
。因此,結果索引為(-1-1)
或-2.
此方法的最後一種情況是目標值不存在且小於數組中的最小值:
@Test
void givenIntegerArray_whenUseBinarySearch_thenWillGetLowerBoundMinusIndex() {
int[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(-1, Arrays.binarySearch(numbers, -15));
}
在這種情況下,我們得到-1
因為我們的目標值小於數組中的最小值。
5. 使用IntStream
在下面的測試代碼中,我們將使用IntStream
接口。這個接口是在 Java 8 中引入的。從IntStream
接口,我們將使用range()
方法。 range()
方法生成從 0(含)到arr.length
(不含)的有序整數流。
首先,我們將實現一個使用IntStream.range()
迭代輸入數組的方法:
static int intStream(int[] numbers, int target) {
return IntStream.range(0, numbers.length)
.filter(i -> numbers[i] == target)
.findFirst()
.orElse(-1);
}
range()
方法生成的整數表示numbers
數組的索引。然後filter()
方法檢查索引i
處的元素是否等於目標值。如果目標元素不在數組中,則orElse()
返回-1
。最後,使用findFirst(
),我們得到第一個等於目標值的元素。
使用我們的intStream()
方法,我們可以實現下一個測試用例:
@Test
void givenIntegerArray_whenUseIntStream_thenWillGetElementIndex() {
int[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(2, intStream(numbers, 30));
}
在我們的測試代碼中,我們調用了我們實現的intStream()
方法,我們得到了放置目標元素的索引。如果目標元素不在數組中,那麼我們將得到-1
;
6.Apache 公共圖書館
至此,我們已經了解了大多數可用於查找數組中元素索引的內置 Java API。但是,我們可以使用第三方庫來查找數組中元素的索引。
Apache Commons Lang 3 是一個有用的第三方庫來完成我們想要的行為。在我們實施測試用例之前,我們需要將Apache Commons Lang 依賴項添加到我們的pom.xml
文件中:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
在我們的測試用例中,我們使用ArrayUtils
類中的indexOf()
方法。此方法接收一個數組和一個要查找的值作為參數。此外,我們可以傳遞第三個可選參數,即起始索引。
首先,讓我們通過傳遞數組和目標值來測試這個方法:
@Test
void givenIntegerArray_whenUseApacheCommons_thenWillGetElementIndex() {
int[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(2, ArrayUtils.indexOf(numbers, 30));
}
在上面的測試用例中,我們尋找目標值 30。執行測試後,我們得到期望值2
。
在第二個測試用例中,我們為indexOf()
方法傳遞起始索引。我們的目標值與第一個測試相同,起始索引為3
:
@Test
void givenIntegerArray_whenUseApacheCommonsStartingFromIndex_thenWillGetNegativeIndex() {
int[] numbers = { 10, 20, 30, 40, 50 };
assertEquals(-1, ArrayUtils.indexOf(numbers, 30, 3));
}
將起始位置設置為3
後,我們注意到無法找到目標值,因為indexOf()
從數組中的值 40 開始。然後在執行測試後,我們得到一個-1
索引,表明該值不在集合中。
七、性能比較
最後,我們將使用算法複雜性分析中的大 O 表示法快速回顧我們解決方案的性能:
方法 | 複雜性(大O) | |
時間 | 空間 | |
for 循環 | O(n) | O(1) |
List indexOf() | O(n) | O(n) |
Arrays binarySearch() | O(log n) | O(1) |
IntStream | O(n) | O(1) |
Apache Commons indexOf() | O(n) | O(1) |
我們見過的所有解決方案都具有O(n)
時間複雜度,除了二分查找的情況,其具有O(log n)
。但是,在二分搜索的情況下,輸入數組必須先排序。
在空間複雜度的情況下,所有解決方案都具有O(1)
或常數時間複雜度,但listIndexOf()
方法的情況除外,即O(n)
。對於後一種方法,空間複雜度來自於將輸入數組轉換為列表。
八、結論
在本文中,我們實現了一些方法來查找 Java 數組中元素的索引。我們使用 Java 內置 API 和 Apache Commons 作為第三方庫。此外,我們對我們的解決方案進行了時空複雜性分析。
在決定在您的應用程序中使用哪一個之前,必須仔細評估這些庫的功能和性能特徵。
與往常一樣,本文中使用的所有代碼片段都可以在 GitHub 上找到。