Skip to content

4.1   Arrays

The "array" is a linear data structure that stores elements of the same type in contiguous memory locations. We refer to the position of an element in the array as its "index". The following image illustrates the main terminology and concepts of an array.

Array Definition and Storage Method

Figure 4-1   Array Definition and Storage Method

4.1.1   Common Operations on Arrays

1.   Initializing Arrays

There are two ways to initialize arrays depending on the requirements: without initial values and with given initial values. In cases where initial values are not specified, most programming languages will initialize the array elements to \(0\):

array.py
# Initialize array
arr: list[int] = [0] * 5  # [ 0, 0, 0, 0, 0 ]
nums: list[int] = [1, 3, 2, 5, 4]
array.cpp
/* Initialize array */
// Stored on stack
int arr[5];
int nums[5] = { 1, 3, 2, 5, 4 };
// Stored on heap (manual memory release needed)
int* arr1 = new int[5];
int* nums1 = new int[5] { 1, 3, 2, 5, 4 };
array.java
/* Initialize array */
int[] arr = new int[5]; // { 0, 0, 0, 0, 0 }
int[] nums = { 1, 3, 2, 5, 4 };
array.cs
/* Initialize array */
int[] arr = new int[5]; // [ 0, 0, 0, 0, 0 ]
int[] nums = [1, 3, 2, 5, 4];
array.go
/* Initialize array */
var arr [5]int
// In Go, specifying the length ([5]int) denotes an array, while not specifying it ([]int) denotes a slice.
// Since Go's arrays are designed to have compile-time fixed length, only constants can be used to specify the length.
// For convenience in implementing the extend() method, the Slice will be considered as an Array here.
nums := []int{1, 3, 2, 5, 4}
array.swift
/* Initialize array */
let arr = Array(repeating: 0, count: 5) // [0, 0, 0, 0, 0]
let nums = [1, 3, 2, 5, 4]
array.js
/* Initialize array */
var arr = new Array(5).fill(0);
var nums = [1, 3, 2, 5, 4];
array.ts
/* Initialize array */
let arr: number[] = new Array(5).fill(0);
let nums: number[] = [1, 3, 2, 5, 4];
array.dart
/* Initialize array */
List<int> arr = List.filled(5, 0); // [0, 0, 0, 0, 0]
List<int> nums = [1, 3, 2, 5, 4];
array.rs
/* Initialize array */
let arr: Vec<i32> = vec![0; 5]; // [0, 0, 0, 0, 0]
let nums: Vec<i32> = vec![1, 3, 2, 5, 4];
array.c
/* Initialize array */
int arr[5] = { 0 }; // { 0, 0, 0, 0, 0 }
int nums[5] = { 1, 3, 2, 5, 4 };
array.zig
// Initialize array
var arr = [_]i32{0} ** 5; // { 0, 0, 0, 0, 0 }
var nums = [_]i32{ 1, 3, 2, 5, 4 };

2.   Accessing Elements

Elements in an array are stored in contiguous memory locations, which makes it easy to compute the memory address of any element. Given the memory address of the array (the address of the first element) and the index of an element, we can calculate the memory address of that element using the formula shown in the following image, allowing direct access to the element.

Memory Address Calculation for Array Elements

Figure 4-2   Memory Address Calculation for Array Elements

As observed in the above image, the index of the first element of an array is \(0\), which may seem counterintuitive since counting starts from \(1\). However, from the perspective of the address calculation formula, an index is essentially an offset from the memory address. The offset for the first element's address is \(0\), making its index \(0\) logical.

Accessing elements in an array is highly efficient, allowing us to randomly access any element in \(O(1)\) time.

array.py
def random_access(nums: list[int]) -> int:
    """随机访问元素"""
    # 在区间 [0, len(nums)-1] 中随机抽取一个数字
    random_index = random.randint(0, len(nums) - 1)
    # 获取并返回随机元素
    random_num = nums[random_index]
    return random_num
array.cpp
/* 随机访问元素 */
int randomAccess(int *nums, int size) {
    // 在区间 [0, size) 中随机抽取一个数字
    int randomIndex = rand() % size;
    // 获取并返回随机元素
    int randomNum = nums[randomIndex];
    return randomNum;
}
array.java
/* 随机访问元素 */
int randomAccess(int[] nums) {
    // 在区间 [0, nums.length) 中随机抽取一个数字
    int randomIndex = ThreadLocalRandom.current().nextInt(0, nums.length);
    // 获取并返回随机元素
    int randomNum = nums[randomIndex];
    return randomNum;
}
array.cs
/* 随机访问元素 */
int RandomAccess(int[] nums) {
    Random random = new();
    // 在区间 [0, nums.Length) 中随机抽取一个数字
    int randomIndex = random.Next(nums.Length);
    // 获取并返回随机元素
    int randomNum = nums[randomIndex];
    return randomNum;
}
array.go
/* 随机访问元素 */
func randomAccess(nums []int) (randomNum int) {
    // 在区间 [0, nums.length) 中随机抽取一个数字
    randomIndex := rand.Intn(len(nums))
    // 获取并返回随机元素
    randomNum = nums[randomIndex]
    return
}
array.swift
/* 随机访问元素 */
func randomAccess(nums: [Int]) -> Int {
    // 在区间 [0, nums.count) 中随机抽取一个数字
    let randomIndex = nums.indices.randomElement()!
    // 获取并返回随机元素
    let randomNum = nums[randomIndex]
    return randomNum
}
array.js
/* 随机访问元素 */
function randomAccess(nums) {
    // 在区间 [0, nums.length) 中随机抽取一个数字
    const random_index = Math.floor(Math.random() * nums.length);
    // 获取并返回随机元素
    const random_num = nums[random_index];
    return random_num;
}
array.ts
/* 随机访问元素 */
function randomAccess(nums: number[]): number {
    // 在区间 [0, nums.length) 中随机抽取一个数字
    const random_index = Math.floor(Math.random() * nums.length);
    // 获取并返回随机元素
    const random_num = nums[random_index];
    return random_num;
}
array.dart
/* 随机访问元素 */
int randomAccess(List<int> nums) {
  // 在区间 [0, nums.length) 中随机抽取一个数字
  int randomIndex = Random().nextInt(nums.length);
  // 获取并返回随机元素
  int randomNum = nums[randomIndex];
  return randomNum;
}
array.rs
/* 随机访问元素 */
fn random_access(nums: &[i32]) -> i32 {
    // 在区间 [0, nums.len()) 中随机抽取一个数字
    let random_index = rand::thread_rng().gen_range(0..nums.len());
    // 获取并返回随机元素
    let random_num = nums[random_index];
    random_num
}
array.c
/* 随机访问元素 */
int randomAccess(int *nums, int size) {
    // 在区间 [0, size) 中随机抽取一个数字
    int randomIndex = rand() % size;
    // 获取并返回随机元素
    int randomNum = nums[randomIndex];
    return randomNum;
}
array.zig
// 随机访问元素
fn randomAccess(nums: []i32) i32 {
    // 在区间 [0, nums.len) 中随机抽取一个整数
    var randomIndex = std.crypto.random.intRangeLessThan(usize, 0, nums.len);
    // 获取并返回随机元素
    var randomNum = nums[randomIndex];
    return randomNum;
}
Visualizing Code

全屏观看 >

3.   Inserting Elements

As shown in the image below, to insert an element in the middle of an array, all elements following the insertion point must be moved one position back to make room for the new element.

Array Element Insertion Example

Figure 4-3   Array Element Insertion Example

It's important to note that since the length of an array is fixed, inserting an element will inevitably lead to the loss of the last element in the array. We will discuss solutions to this problem in the "List" chapter.

array.py
def insert(nums: list[int], num: int, index: int):
    """在数组的索引 index 处插入元素 num"""
    # 把索引 index 以及之后的所有元素向后移动一位
    for i in range(len(nums) - 1, index, -1):
        nums[i] = nums[i - 1]
    # 将 num 赋给 index 处的元素
    nums[index] = num
array.cpp
/* 在数组的索引 index 处插入元素 num */
void insert(int *nums, int size, int num, int index) {
    // 把索引 index 以及之后的所有元素向后移动一位
    for (int i = size - 1; i > index; i--) {
        nums[i] = nums[i - 1];
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num;
}
array.java
/* 在数组的索引 index 处插入元素 num */
void insert(int[] nums, int num, int index) {
    // 把索引 index 以及之后的所有元素向后移动一位
    for (int i = nums.length - 1; i > index; i--) {
        nums[i] = nums[i - 1];
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num;
}
array.cs
/* 在数组的索引 index 处插入元素 num */
void Insert(int[] nums, int num, int index) {
    // 把索引 index 以及之后的所有元素向后移动一位
    for (int i = nums.Length - 1; i > index; i--) {
        nums[i] = nums[i - 1];
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num;
}
array.go
/* 在数组的索引 index 处插入元素 num */
func insert(nums []int, num int, index int) {
    // 把索引 index 以及之后的所有元素向后移动一位
    for i := len(nums) - 1; i > index; i-- {
        nums[i] = nums[i-1]
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num
}
array.swift
/* 在数组的索引 index 处插入元素 num */
func insert(nums: inout [Int], num: Int, index: Int) {
    // 把索引 index 以及之后的所有元素向后移动一位
    for i in nums.indices.dropFirst(index).reversed() {
        nums[i] = nums[i - 1]
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num
}
array.js
/* 在数组的索引 index 处插入元素 num */
function insert(nums, num, index) {
    // 把索引 index 以及之后的所有元素向后移动一位
    for (let i = nums.length - 1; i > index; i--) {
        nums[i] = nums[i - 1];
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num;
}
array.ts
/* 在数组的索引 index 处插入元素 num */
function insert(nums: number[], num: number, index: number): void {
    // 把索引 index 以及之后的所有元素向后移动一位
    for (let i = nums.length - 1; i > index; i--) {
        nums[i] = nums[i - 1];
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num;
}
array.dart
/* 在数组的索引 index 处插入元素 _num */
void insert(List<int> nums, int _num, int index) {
  // 把索引 index 以及之后的所有元素向后移动一位
  for (var i = nums.length - 1; i > index; i--) {
    nums[i] = nums[i - 1];
  }
  // 将 _num 赋给 index 处元素
  nums[index] = _num;
}
array.rs
/* 在数组的索引 index 处插入元素 num */
fn insert(nums: &mut Vec<i32>, num: i32, index: usize) {
    // 把索引 index 以及之后的所有元素向后移动一位
    for i in (index + 1..nums.len()).rev() {
        nums[i] = nums[i - 1];
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num;
}
array.c
/* 在数组的索引 index 处插入元素 num */
void insert(int *nums, int size, int num, int index) {
    // 把索引 index 以及之后的所有元素向后移动一位
    for (int i = size - 1; i > index; i--) {
        nums[i] = nums[i - 1];
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num;
}
array.zig
// 在数组的索引 index 处插入元素 num
fn insert(nums: []i32, num: i32, index: usize) void {
    // 把索引 index 以及之后的所有元素向后移动一位
    var i = nums.len - 1;
    while (i > index) : (i -= 1) {
        nums[i] = nums[i - 1];
    }
    // 将 num 赋给 index 处的元素
    nums[index] = num;
}
Visualizing Code

全屏观看 >

4.   Deleting Elements

Similarly, as illustrated below, to delete an element at index \(i\), all elements following index \(i\) must be moved forward by one position.

Array Element Deletion Example

Figure 4-4   Array Element Deletion Example

Note that after deletion, the last element becomes "meaningless", so we do not need to specifically modify it.

array.py
def remove(nums: list[int], index: int):
    """删除索引 index 处的元素"""
    # 把索引 index 之后的所有元素向前移动一位
    for i in range(index, len(nums) - 1):
        nums[i] = nums[i + 1]
array.cpp
/* 删除索引 index 处的元素 */
void remove(int *nums, int size, int index) {
    // 把索引 index 之后的所有元素向前移动一位
    for (int i = index; i < size - 1; i++) {
        nums[i] = nums[i + 1];
    }
}
array.java
/* 删除索引 index 处的元素 */
void remove(int[] nums, int index) {
    // 把索引 index 之后的所有元素向前移动一位
    for (int i = index; i < nums.length - 1; i++) {
        nums[i] = nums[i + 1];
    }
}
array.cs
/* 删除索引 index 处的元素 */
void Remove(int[] nums, int index) {
    // 把索引 index 之后的所有元素向前移动一位
    for (int i = index; i < nums.Length - 1; i++) {
        nums[i] = nums[i + 1];
    }
}
array.go
/* 删除索引 index 处的元素 */
func remove(nums []int, index int) {
    // 把索引 index 之后的所有元素向前移动一位
    for i := index; i < len(nums)-1; i++ {
        nums[i] = nums[i+1]
    }
}
array.swift
/* 删除索引 index 处的元素 */
func remove(nums: inout [Int], index: Int) {
    // 把索引 index 之后的所有元素向前移动一位
    for i in nums.indices.dropFirst(index).dropLast() {
        nums[i] = nums[i + 1]
    }
}
array.js
/* 删除索引 index 处的元素 */
function remove(nums, index) {
    // 把索引 index 之后的所有元素向前移动一位
    for (let i = index; i < nums.length - 1; i++) {
        nums[i] = nums[i + 1];
    }
}
array.ts
/* 删除索引 index 处的元素 */
function remove(nums: number[], index: number): void {
    // 把索引 index 之后的所有元素向前移动一位
    for (let i = index; i < nums.length - 1; i++) {
        nums[i] = nums[i + 1];
    }
}
array.dart
/* 删除索引 index 处的元素 */
void remove(List<int> nums, int index) {
  // 把索引 index 之后的所有元素向前移动一位
  for (var i = index; i < nums.length - 1; i++) {
    nums[i] = nums[i + 1];
  }
}
array.rs
/* 删除索引 index 处的元素 */
fn remove(nums: &mut Vec<i32>, index: usize) {
    // 把索引 index 之后的所有元素向前移动一位
    for i in index..nums.len() - 1 {
        nums[i] = nums[i + 1];
    }
}
array.c
/* 删除索引 index 处的元素 */
// 注意:stdio.h 占用了 remove 关键词
void removeItem(int *nums, int size, int index) {
    // 把索引 index 之后的所有元素向前移动一位
    for (int i = index; i < size - 1; i++) {
        nums[i] = nums[i + 1];
    }
}
array.zig
// 删除索引 index 处的元素
fn remove(nums: []i32, index: usize) void {
    // 把索引 index 之后的所有元素向前移动一位
    var i = index;
    while (i < nums.len - 1) : (i += 1) {
        nums[i] = nums[i + 1];
    }
}
Visualizing Code

全屏观看 >

Overall, the insertion and deletion operations in arrays have the following disadvantages:

  • High Time Complexity: Both insertion and deletion in an array have an average time complexity of \(O(n)\), where \(n\) is the length of the array.
  • Loss of Elements: Due to the fixed length of arrays, elements that exceed the array's capacity are lost during insertion.
  • Waste of Memory: We can initialize a longer array and use only the front part, allowing the "lost" end elements during insertion to be "meaningless", but this leads to some wasted memory space.

5.   Traversing Arrays

In most programming languages, we can traverse an array either by indices or by directly iterating over each element:

array.py
def traverse(nums: list[int]):
    """遍历数组"""
    count = 0
    # 通过索引遍历数组
    for i in range(len(nums)):
        count += nums[i]
    # 直接遍历数组元素
    for num in nums:
        count += num
    # 同时遍历数据索引和元素
    for i, num in enumerate(nums):
        count += nums[i]
        count += num
array.cpp
/* 遍历数组 */
void traverse(int *nums, int size) {
    int count = 0;
    // 通过索引遍历数组
    for (int i = 0; i < size; i++) {
        count += nums[i];
    }
}
array.java
/* 遍历数组 */
void traverse(int[] nums) {
    int count = 0;
    // 通过索引遍历数组
    for (int i = 0; i < nums.length; i++) {
        count += nums[i];
    }
    // 直接遍历数组元素
    for (int num : nums) {
        count += num;
    }
}
array.cs
/* 遍历数组 */
void Traverse(int[] nums) {
    int count = 0;
    // 通过索引遍历数组
    for (int i = 0; i < nums.Length; i++) {
        count += nums[i];
    }
    // 直接遍历数组元素
    foreach (int num in nums) {
        count += num;
    }
}
array.go
/* 遍历数组 */
func traverse(nums []int) {
    count := 0
    // 通过索引遍历数组
    for i := 0; i < len(nums); i++ {
        count += nums[i]
    }
    count = 0
    // 直接遍历数组元素
    for _, num := range nums {
        count += num
    }
    // 同时遍历数据索引和元素
    for i, num := range nums {
        count += nums[i]
        count += num
    }
}
array.swift
/* 遍历数组 */
func traverse(nums: [Int]) {
    var count = 0
    // 通过索引遍历数组
    for i in nums.indices {
        count += nums[i]
    }
    // 直接遍历数组元素
    for num in nums {
        count += num
    }
}
array.js
/* 遍历数组 */
function traverse(nums) {
    let count = 0;
    // 通过索引遍历数组
    for (let i = 0; i < nums.length; i++) {
        count += nums[i];
    }
    // 直接遍历数组元素
    for (const num of nums) {
        count += num;
    }
}
array.ts
/* 遍历数组 */
function traverse(nums: number[]): void {
    let count = 0;
    // 通过索引遍历数组
    for (let i = 0; i < nums.length; i++) {
        count += nums[i];
    }
    // 直接遍历数组元素
    for (const num of nums) {
        count += num;
    }
}
array.dart
/* 遍历数组元素 */
void traverse(List<int> nums) {
  int count = 0;
  // 通过索引遍历数组
  for (var i = 0; i < nums.length; i++) {
    count += nums[i];
  }
  // 直接遍历数组元素
  for (int _num in nums) {
    count += _num;
  }
  // 通过 forEach 方法遍历数组
  nums.forEach((_num) {
    count += _num;
  });
}
array.rs
/* 遍历数组 */
fn traverse(nums: &[i32]) {
    let mut _count = 0;
    // 通过索引遍历数组
    for i in 0..nums.len() {
        _count += nums[i];
    }
    // 直接遍历数组元素
    for num in nums {
        _count += num;
    }
}
array.c
/* 遍历数组 */
void traverse(int *nums, int size) {
    int count = 0;
    // 通过索引遍历数组
    for (int i = 0; i < size; i++) {
        count += nums[i];
    }
}
array.zig
// 遍历数组
fn traverse(nums: []i32) void {
    var count: i32 = 0;
    // 通过索引遍历数组
    var i: i32 = 0;
    while (i < nums.len) : (i += 1) {
        count += nums[i];
    }
    count = 0;
    // 直接遍历数组元素
    for (nums) |num| {
        count += num;
    }
}
Visualizing Code

全屏观看 >

6.   Finding Elements

To find a specific element in an array, we need to iterate through it, checking each element to see if it matches.

Since arrays are linear data structures, this operation is known as "linear search".

array.py
def find(nums: list[int], target: int) -> int:
    """在数组中查找指定元素"""
    for i in range(len(nums)):
        if nums[i] == target:
            return i
    return -1
array.cpp
/* 在数组中查找指定元素 */
int find(int *nums, int size, int target) {
    for (int i = 0; i < size; i++) {
        if (nums[i] == target)
            return i;
    }
    return -1;
}
array.java
/* 在数组中查找指定元素 */
int find(int[] nums, int target) {
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] == target)
            return i;
    }
    return -1;
}
array.cs
/* 在数组中查找指定元素 */
int Find(int[] nums, int target) {
    for (int i = 0; i < nums.Length; i++) {
        if (nums[i] == target)
            return i;
    }
    return -1;
}
array.go
/* 在数组中查找指定元素 */
func find(nums []int, target int) (index int) {
    index = -1
    for i := 0; i < len(nums); i++ {
        if nums[i] == target {
            index = i
            break
        }
    }
    return
}
array.swift
/* 在数组中查找指定元素 */
func find(nums: [Int], target: Int) -> Int {
    for i in nums.indices {
        if nums[i] == target {
            return i
        }
    }
    return -1
}
array.js
/* 在数组中查找指定元素 */
function find(nums, target) {
    for (let i = 0; i < nums.length; i++) {
        if (nums[i] === target) return i;
    }
    return -1;
}
array.ts
/* 在数组中查找指定元素 */
function find(nums: number[], target: number): number {
    for (let i = 0; i < nums.length; i++) {
        if (nums[i] === target) {
            return i;
        }
    }
    return -1;
}
array.dart
/* 在数组中查找指定元素 */
int find(List<int> nums, int target) {
  for (var i = 0; i < nums.length; i++) {
    if (nums[i] == target) return i;
  }
  return -1;
}
array.rs
/* 在数组中查找指定元素 */
fn find(nums: &[i32], target: i32) -> Option<usize> {
    for i in 0..nums.len() {
        if nums[i] == target {
            return Some(i);
        }
    }
    None
}
array.c
/* 在数组中查找指定元素 */
int find(int *nums, int size, int target) {
    for (int i = 0; i < size; i++) {
        if (nums[i] == target)
            return i;
    }
    return -1;
}
array.zig
// 在数组中查找指定元素
fn find(nums: []i32, target: i32) i32 {
    for (nums, 0..) |num, i| {
        if (num == target) return @intCast(i);
    }
    return -1;
}
Visualizing Code

全屏观看 >

7.   Expanding Arrays

In complex system environments, it's challenging to ensure that the memory space following an array is available, making it unsafe to extend the array's capacity. Therefore, in most programming languages, the length of an array is immutable.

To expand an array, we need to create a larger array and then copy the elements from the original array. This operation has a time complexity of \(O(n)\) and can be time-consuming for large arrays. The code is as follows:

array.py
def extend(nums: list[int], enlarge: int) -> list[int]:
    """扩展数组长度"""
    # 初始化一个扩展长度后的数组
    res = [0] * (len(nums) + enlarge)
    # 将原数组中的所有元素复制到新数组
    for i in range(len(nums)):
        res[i] = nums[i]
    # 返回扩展后的新数组
    return res
array.cpp
/* 扩展数组长度 */
int *extend(int *nums, int size, int enlarge) {
    // 初始化一个扩展长度后的数组
    int *res = new int[size + enlarge];
    // 将原数组中的所有元素复制到新数组
    for (int i = 0; i < size; i++) {
        res[i] = nums[i];
    }
    // 释放内存
    delete[] nums;
    // 返回扩展后的新数组
    return res;
}
array.java
/* 扩展数组长度 */
int[] extend(int[] nums, int enlarge) {
    // 初始化一个扩展长度后的数组
    int[] res = new int[nums.length + enlarge];
    // 将原数组中的所有元素复制到新数组
    for (int i = 0; i < nums.length; i++) {
        res[i] = nums[i];
    }
    // 返回扩展后的新数组
    return res;
}
array.cs
/* 扩展数组长度 */
int[] Extend(int[] nums, int enlarge) {
    // 初始化一个扩展长度后的数组
    int[] res = new int[nums.Length + enlarge];
    // 将原数组中的所有元素复制到新数组
    for (int i = 0; i < nums.Length; i++) {
        res[i] = nums[i];
    }
    // 返回扩展后的新数组
    return res;
}
array.go
/* 扩展数组长度 */
func extend(nums []int, enlarge int) []int {
    // 初始化一个扩展长度后的数组
    res := make([]int, len(nums)+enlarge)
    // 将原数组中的所有元素复制到新数组
    for i, num := range nums {
        res[i] = num
    }
    // 返回扩展后的新数组
    return res
}
array.swift
/* 扩展数组长度 */
func extend(nums: [Int], enlarge: Int) -> [Int] {
    // 初始化一个扩展长度后的数组
    var res = Array(repeating: 0, count: nums.count + enlarge)
    // 将原数组中的所有元素复制到新数组
    for i in nums.indices {
        res[i] = nums[i]
    }
    // 返回扩展后的新数组
    return res
}
array.js
/* 扩展数组长度 */
// 请注意,JavaScript 的 Array 是动态数组,可以直接扩展
// 为了方便学习,本函数将 Array 看作长度不可变的数组
function extend(nums, enlarge) {
    // 初始化一个扩展长度后的数组
    const res = new Array(nums.length + enlarge).fill(0);
    // 将原数组中的所有元素复制到新数组
    for (let i = 0; i < nums.length; i++) {
        res[i] = nums[i];
    }
    // 返回扩展后的新数组
    return res;
}
array.ts
/* 扩展数组长度 */
// 请注意,TypeScript 的 Array 是动态数组,可以直接扩展
// 为了方便学习,本函数将 Array 看作长度不可变的数组
function extend(nums: number[], enlarge: number): number[] {
    // 初始化一个扩展长度后的数组
    const res = new Array(nums.length + enlarge).fill(0);
    // 将原数组中的所有元素复制到新数组
    for (let i = 0; i < nums.length; i++) {
        res[i] = nums[i];
    }
    // 返回扩展后的新数组
    return res;
}
array.dart
/* 扩展数组长度 */
List<int> extend(List<int> nums, int enlarge) {
  // 初始化一个扩展长度后的数组
  List<int> res = List.filled(nums.length + enlarge, 0);
  // 将原数组中的所有元素复制到新数组
  for (var i = 0; i < nums.length; i++) {
    res[i] = nums[i];
  }
  // 返回扩展后的新数组
  return res;
}
array.rs
/* 扩展数组长度 */
fn extend(nums: Vec<i32>, enlarge: usize) -> Vec<i32> {
    // 初始化一个扩展长度后的数组
    let mut res: Vec<i32> = vec![0; nums.len() + enlarge];
    // 将原数组中的所有元素复制到新
    for i in 0..nums.len() {
        res[i] = nums[i];
    }
    // 返回扩展后的新数组
    res
}
array.c
/* 扩展数组长度 */
int *extend(int *nums, int size, int enlarge) {
    // 初始化一个扩展长度后的数组
    int *res = (int *)malloc(sizeof(int) * (size + enlarge));
    // 将原数组中的所有元素复制到新数组
    for (int i = 0; i < size; i++) {
        res[i] = nums[i];
    }
    // 初始化扩展后的空间
    for (int i = size; i < size + enlarge; i++) {
        res[i] = 0;
    }
    // 返回扩展后的新数组
    return res;
}
array.zig
// 扩展数组长度
fn extend(mem_allocator: std.mem.Allocator, nums: []i32, enlarge: usize) ![]i32 {
    // 初始化一个扩展长度后的数组
    var res = try mem_allocator.alloc(i32, nums.len + enlarge);
    @memset(res, 0);
    // 将原数组中的所有元素复制到新数组
    std.mem.copy(i32, res, nums);
    // 返回扩展后的新数组
    return res;
}
Visualizing Code

全屏观看 >

4.1.2   Advantages and Limitations of Arrays

Arrays are stored in contiguous memory spaces and consist of elements of the same type. This approach includes a wealth of prior information that the system can use to optimize the operation efficiency of the data structure.

  • High Space Efficiency: Arrays allocate a contiguous block of memory for data, eliminating the need for additional structural overhead.
  • Support for Random Access: Arrays allow \(O(1)\) time access to any element.
  • Cache Locality: When accessing array elements, the computer not only loads them but also caches the surrounding data, leveraging high-speed cache to improve the speed of subsequent operations.

However, continuous space storage is a double-edged sword, with the following limitations:

  • Low Efficiency in Insertion and Deletion: When there are many elements in an array, insertion and deletion operations require moving a large number of elements.
  • Fixed Length: The length of an array is fixed after initialization. Expanding an array requires copying all data to a new array, which is costly.
  • Space Wastage: If the allocated size of an array exceeds the actual need, the extra space is wasted.

4.1.3   Typical Applications of Arrays

Arrays are a fundamental and common data structure, frequently used in various algorithms and in implementing complex data structures.

  • Random Access: If we want to randomly sample some data, we can use an array for storage and generate a random sequence to implement random sampling based on indices.
  • Sorting and Searching: Arrays are the most commonly used data structure for sorting and searching algorithms. Quick sort, merge sort, binary search, etc., are primarily conducted on arrays.
  • Lookup Tables: Arrays can be used as lookup tables for fast element or relationship retrieval. For instance, if we want to implement a mapping from characters to ASCII codes, we can use the ASCII code value of a character as the index, with the corresponding element stored in the corresponding position in the array.
  • Machine Learning: Arrays are extensively used in neural networks for linear algebra operations between vectors, matrices, and tensors. Arrays are the most commonly used data structure in neural network programming.
  • Data Structure Implementation: Arrays can be used to implement stacks, queues, hash tables, heaps, graphs, etc. For example, the adjacency matrix representation of a graph is essentially a two-dimensional array.
Feel free to drop your insights, questions or suggestions