Bootstrap

数据结构第04节:数组

线性数据结构 - 数组

线性数据结构中的数组是一种基础且广泛使用的数据存储方式,它存储一系列相同类型的元素,这些元素在内存中连续存放。数组可以是静态的或动态的。

静态数组(Static Arrays)

静态数组在声明时需要指定大小,并且一旦声明,其大小就不能改变。

Demo1

想象一下超市里的货架,每个货架上都有一定数量的格子,每个格子可以放置一个商品。如果货架已经放满了,你就不能在这个货架上再添加更多的商品了,除非你更换一个更大的货架,这类似于Java中的静态数组。

Java源代码
public class StaticArrayExample {
    public static void main(String[] args) {
        // 声明并初始化一个静态数组
        int[] scores = {85, 92, 76, 88, 91};

        // 访问数组元素
        System.out.println("Score at index 2: " + scores[2]); // 输出 76

        // 尝试修改数组大小
        // scores = new int[10]; // 这将创建一个新的数组,但原始数组仍然保持不变

        // 打印数组中的所有元素
        for (int score : scores) {
            System.out.print(score + " ");
        }
    }
}
动态数组(Dynamic Arrays)

动态数组是一种可以自动调整大小的数组。在Java中,ArrayList是动态数组的一个实现。

Demo2

考虑一个不断增长的图书馆书架,随着新书的添加,书架可能需要扩展。这就像Java中的动态数组,随着元素的添加,数组会自动增加容量。

Java源代码
import java.util.ArrayList;

public class DynamicArrayExample {
    public static void main(String[] args) {
        // 创建一个动态数组(ArrayList)
        ArrayList<String> books = new ArrayList<>();

        // 向动态数组添加元素
        books.add("1984");
        books.add("Brave New World");
        books.add("Fahrenheit 451");

        // 访问数组元素
        System.out.println("Book at index 1: " + books.get(1)); // 输出 Brave New World

        // 动态数组可以自动调整大小
        books.add("To Kill a Mockingbird");

        // 打印数组中的所有元素
        for (String book : books) {
            System.out.print(book + " ");
        }
    }
}

数组的优势和局限

  • 优势

    • 直接通过索引访问元素,访问速度快。
    • 内存空间连续,利于缓存优化。
  • 局限

    • 静态数组大小固定,不能动态扩展。
    • 动态数组虽然可以动态扩展,但每次扩展都需要创建新的数组并复制旧元素,这可能导致性能开销。

数组是许多其他数据结构的基础,如字符串、矩阵等。在实际编程中,根据需求选择使用静态数组还是动态数组是非常重要的。例如,如果你知道数据的确切大小,使用静态数组可能更合适;如果你需要一个可以动态增长的数据集合,使用动态数组(如Java中的ArrayList)可能更合适。

接下来,我们可以进一步讨论数组的更多特性和操作,包括数组的初始化、遍历、搜索、排序和多维数组的使用。

数组的初始化

在Java中,数组可以在声明时初始化,也可以先声明后初始化。

// 在声明时初始化数组
int[] staticArray = new int[] {1, 2, 3, 4, 5};

// 先声明后初始化
int[] anotherStaticArray;
anotherStaticArray = new int[5]; // 初始化数组大小,但未设置具体值

数组的遍历

遍历数组是访问数组中每个元素的基本操作。

int[] numbers = {1, 2, 3, 4, 5};
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

数组的搜索

在数组中搜索特定元素是常见的操作,可以通过遍历数组来实现。

boolean contains = false;
for (int num : numbers) {
    if (num == 3) {
        contains = true;
        break;
    }
}
System.out.println("Contains 3: " + contains);

数组的排序

Java提供了多种排序算法,如Arrays.sort(),可以对数组进行排序。

import java.util.Arrays;

int[] numbersToSort = {5, 3, 8, 1, 2};
Arrays.sort(numbersToSort);
System.out.println("Sorted array: " + Arrays.toString(numbersToSort));

多维数组

Java支持多维数组,最常见的是二维数组,类似于矩阵。

// 声明并初始化二维数组
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// 访问二维数组的元素
System.out.println("Element at [1][2]: " + matrix[1][2]); // 输出 6

// 遍历二维数组
for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        System.out.print(matrix[i][j] + " ");
    }
    System.out.println();
}

数组的复制

Java提供了System.arraycopy()方法来复制数组。

int[] original = {1, 2, 3, 4, 5};
int[] copy = new int[original.length];
System.arraycopy(original, 0, copy, 0, original.length);

// 验证复制
System.out.println("Original array: " + Arrays.toString(original));
System.out.println("Copied array: " + Arrays.toString(copy));

数组的内存视图

Java的数组是对象,可以通过equals()方法比较数组的内容,但通常使用Arrays.equals()来比较数组是否相等。

int[] array1 = {1, 2, 3};
int[] array2 = {1, 2, 3};
boolean areEqual = Arrays.equals(array1, array2); // true
System.out.println("Are the arrays equal? " + areEqual);

数组是Java中非常重要的数据结构,它们提供了快速访问元素的能力,但同时也需要注意它们的局限性,如固定大小和内存连续性。通过上述代码示例,我们可以看到如何在Java中操作数组,包括初始化、遍历、搜索、排序、复制和比较。这些操作是处理数组时的基础,也是理解更复杂数据结构的基础。

让我们通过Java代码来进一步探讨数组的使用,包括数组的逆序、数组的旋转以及数组的动态扩展。

数组的逆序

逆序数组是一个常见的任务,可以通过循环来实现。

public void reverseArray(int[] array) {
    int temp;
    for (int i = 0; i < array.length / 2; i++) {
        temp = array[i];
        array[i] = array[array.length - 1 - i];
        array[array.length - 1 - i] = temp;
    }
}

使用示例

int[] myArray = {1, 2, 3, 4, 5};
reverseArray(myArray);
System.out.println("Reversed array: " + Arrays.toString(myArray));

数组的旋转

数组的旋转是将数组的元素向右或向左移动指定的步数。

public void rotateArray(int[] array, int steps) {
    reverseArray(array, 0, array.length - 1);
    reverseArray(array, 0, steps - 1);
    reverseArray(array, steps, array.length - 1);
}

private void reverseArray(int[] array, int start, int end) {
    while (start < end) {
        int temp = array[start];
        array[start] = array[end];
        array[end] = temp;
        start++;
        end--;
    }
}

使用示例

int[] myRotatedArray = {1, 2, 3, 4, 5, 6, 7};
rotateArray(myRotatedArray, 3);
System.out.println("Rotated array: " + Arrays.toString(myRotatedArray));

数组的动态扩展

虽然Java的数组本身不支持动态扩展,但我们可以通过创建一个新的数组并将旧数组的内容复制到新数组中来实现。

public int[] expandArray(int[] original, int newSize) {
    int[] expanded = new int[newSize];
    for (int i = 0; i < original.length && i < newSize; i++) {
        expanded[i] = original[i];
    }
    return expanded;
}

使用示例

int[] originalArray = {1, 2, 3};
int[] expandedArray = expandArray(originalArray, 5);
System.out.println("Expanded array: " + Arrays.toString(expandedArray));

寻找数组中的最值

在数组中查找最大或最小元素是另一个常见的任务。

public int findMax(int[] array) {
    int max = array[0];
    for (int i = 1; i < array.length; i++) {
        if (array[i] > max) {
            max = array[i];
        }
    }
    return max;
}

public int findMin(int[] array) {
    int min = array[0];
    for (int i = 1; i < array.length; i++) {
        if (array[i] < min) {
            min = array[i];
        }
    }
    return min;
}

使用示例

int[] numbers = {10, 20, 5, 40, 15};
System.out.println("Max value: " + findMax(numbers));
System.out.println("Min value: " + findMin(numbers));

通过这些示例,我们可以看到数组在Java中的多种操作方式,包括逆序、旋转、动态扩展和查找最值。这些操作不仅展示了数组的灵活性,也体现了Java语言在处理数组方面的功能。在实际应用中,根据具体需求选择合适的数组操作是非常重要的。

;