在阅读本文之前,请阅读有关Array Data Structures文章的信息。
阵列是计算机科学和编程中的基本数据结构,提供了一系列优势,劣势和大的复杂性,影响其效率和可用性。
了解数组的特征对于为特定任务选择正确的数据结构和优化程序性能至关重要。
在本文中,我们深入研究了阵列的优势,劣势和大o的复杂性。我们探索阵列提供的好处,例如随机和顺序访问,实现的简单性以及缓存友好性。同时,我们解决了它们的局限性,包括固定尺寸,插入和删除操作挑战和僵化。
此外,我们讨论与常见数组操作相关的时间复杂性,例如访问,搜索,插入,删除和调整大小。通过了解这些方面,程序员在利用数组时可以做出明智的决定,并有效地平衡其应用程序的效率和功能之间的权衡。
优势
使用数组有许多优点,其中一些以下概述:
- 快速查找(随机访问)
- 快速附加
- 简单实施
- 缓存友善
1.快速查找(随机访问)
在给定索引上检索元素需要O(1)时间,而不论阵列的长度如何。
例如:
int[] A = {-1, 7, 9, 100, 1072};
数组具有五个元素,并且数组的长度是使用A.length
(即5
)计算的。由于数组为零索引,因此使用A[A.length - 1]
访问了最后一个元素,该元素是A[4]
,如下所示。
如果我们使用索引(例如A[0]
或A[4]
)访问数组元素,则需要一个时间单元或以大O的方式进行恒定操作。
A[0]; // -1
A[3]; // 100
A[4]; // 1072
A[5]; // Index out of bounds exception, as there is no A[5] value.
上述所有操作都消耗单个时间单位,即o(1)时间。
2.快速附加
如果数组有空间,在数组末尾添加一个新元素需要时间。
让我们创建一个具有5
的数组,并在indexes 0
和1
上插入100
和101
。
以下代码解释了它。
int[] A = new int[5];
A[0] = 100;
A[1] = 101;
现在,如果我们要在数组中插入一个新值,我们可以做A[2] = 200
。在索引2
上插入值200
。该操作消耗一个单位的时间单位。
这是末尾附加的原因。
足够的谈话。这是一种简单的算法,该算法可创建一个带有大小5
的数组,并将100
,101
值插入数组中。最后,我们以数组长度插入一个元素。
import java.util.Arrays;
public class ArrayAppends {
public static void main(String[] args) {
int[] A = new int[5];
int currentLength = 0;
// Let us add 2 elements to the array
for (int i = 0; i < 2; i++) {
A[i] = i + 100;
currentLength++; // when i=1, length is set to 2
}
System.out.println(Arrays.toString(A)); // [100, 101, 0, 0, 0]
System.out.println("current array items length " + currentLength); // 2
System.out.println("Array capacity " + A.length); // 5
System.out.println(
"Element insert at end "
+ Arrays.toString(insertAtEnd(A, currentLength))); // [100, 101, 200, 0, 0]
}
// Inserting element at the end
public static int[] insertAtEnd(int[] A, int currentLength) {
A[currentLength] = 200;
return A;
}
}
/*
Outputs:
[100, 101, 0, 0, 0]
current array items length 2
Array capacity 5
Element insert at end [100, 101, 200, 0, 0]
*/
3.简单的实现
数组在大多数编程语言中都具有直接的实现,使其易于理解和使用。
4.缓存友善
数组中的元素连续存储在内存中,从而改善了缓存性能并可以导致更快的访问时间。
弱点
使用数组有一些偏见,其中一些以下概述:
- 固定尺寸。
- 记忆未使用或浪费。
- 尺寸加倍。
- 昂贵的插入
- 昂贵的删除
1.固定尺寸
数组在创建时定义了固定尺寸。添加或删除超出初始大小的元素需要创建一个新数组并复制现有元素,这可能是效率低下的。
您需要指定提前存储在数组中的多少元素。 (除非您使用了精美的动态数组)。
int[] A = new int[5]; // contains 5 elements
2.记忆未使用或浪费
如果数组的大小大于其包含的元素数量,则浪费了内存。
想象一个具有5
的阵列。我们有两个元素可以存储在此数组中,然后我们浪费了三个未填充的单元格,并且浪费了内存,这意味着浪费了3*(4 bytes) = 12
字节(整数为4
Bytes)。
3.尺寸加倍
让我们考虑一个具有5
元素容量的数组。但是我们要在此数组中存储的元素更多,这意味着我们必须将大小加倍,创建一个新数组,复制旧数组元素并添加新元素。时间复杂性是O(n)
。
您将学习如何将下一课中的数组大小加倍。
4.昂贵的插入物
在数组末尾插入/附加元素需要O(1)
时间。我们已经看到了这一点(快速附加)。
但是,在数组的开始/中插入一个元素需要O(n)
时间。为什么? ðρ
如果我们想将某些内容插入数组中,首先,我们必须通过“踩踏”从我们插入的索引开始的所有内容来制作空间,如图像所示。在最坏的情况下,我们将插入阵列中的0索引(准备),因此我们必须“踩踏”所有内容。那是O(n)
时间。
在第二个索引处插入元素,然后将元素的其余部分移动一次。结果阵列变为{ A, B, C, D, E }
。
在接下来的课程中,您将了解更多有关插入和转移算法的信息,并具有清晰的解释,代码片段和草图,以了解为什么这些插入物在开始时和中间都很昂贵。
5.昂贵的删除
在数组末尾删除元素需要O(1)
时间,这是最好的情况。在计算机科学中,我们只关心从事算法工作时更糟糕的情况。但是,当我们从数组的中间或开始删除一个元素时,我们必须通过在其后的所有元素上踩踏空白来填补空白。如果我们考虑从0
th index删除元素的情况。
O(n)
。
在3
rd索引上删除元素,并通过左移动其余元素来填补空白;结果阵列变为{ A, B, C, D, E }
。
大o复杂性
操作 | 复杂性 | 解释 |
---|---|---|
查找/访问给定索引的值 | o(1) | 通过其索引访问元素是一个恒定的时间操作。 |
在数组中搜索元素 | o(n) | 在未分类数组中搜索特定元素需要迭代 最坏情况下的每个元素。 |
在给定索引上更新值 | o(1) | 在任何给定索引上更新任何元素始终是恒定的时间。 |
在开始/中间 | 插入o(n) | 在数组的开头或中间插入元素需要移动 现有元素,导致线性时间复杂性。 |
在结尾附加 | o(1) | 如果阵列有可用的空间 时间。 |
在开始/中间 | 删除o(n) | 从数组的开头或中间删除元素需要转移 其余元素,导致线性时间复杂性。 |
末端删除 | o(1) | 删除数组的最后一个元素可以在恒定时间内完成。 |
调整大小数组 | o(n) | 调整数组的大小需要创建新数组并复制现有元素, 这需要线性时间。 |
上面提到的BIG-O复杂性用于基本操作,并假设一个未分类的数组。一些专门的数据结构,例如堆或掩盖尺寸,可以为特定用例提供更有效的替代方案。
在接下来的课程中,您将了解有关数组容量与长度,插入和删除算法的更多信息。它们是最简单但最强大的,在处理数组问题时可以帮助您。