深入详细介绍java数组(二)

1. 题记

本博文深入详细介绍java数组,主要介绍java数组在实际开发中的经典使用案例。

2. 数据存储与排序应用

2.1 学生成绩管理系统

假设我们要开发一个简单的学生成绩管理系统,用来存储和处理一个班级学生的各科成绩。可以使用数组来存储学生的成绩信息。例如,用一个二维数组double[][] scores,其中第一维表示学生的编号(索引从 0 开始),第二维表示各科成绩(假设一共有 5 门课程,索引从 0 到 4)。

double[][] scores = new double[30][5];
// 假设给第一个学生的各科成绩赋值
scores[0][0] = 85.0;
scores[0][1] = 90.0;
scores[0][2] = 78.0;
scores[0][3] = 88.0;
scores[0][4] = 92.0;

之后可以使用排序算法(如Arrays.sort()方法)对学生的总成绩进行排序,以方便查看成绩排名。首先需要计算每个学生的总成绩并存储在一个新的数组中,然后对这个数组进行排序。

double[] totalScores = new double[30];
for (int i = 0; i < 30; i++) {
    for (int j = 0; j < 5; j++) {
        totalScores[i] += scores[i][j];
    }
}
Arrays.sort(totalScores);

2.2 员工工资统计:

在一个公司的工资管理系统中,用数组来存储员工的月工资。假设用一个double[] salaries数组,索引代表员工编号,元素值代表工资。

double[] salaries = new double[100];
// 给部分员工工资赋值
salaries[0] = 5000.0;
salaries[1] = 6000.0;

可以对工资数组进行排序,查看工资分布情况。还可以计算平均工资等统计信息。例如,计算平均工资:

double sum = 0;
for (double salary : salaries) {
    sum += salary;
}
double averageSalary = sum / salaries.length;

3. 游戏开发中的应用

3.1 棋盘游戏(如五子棋):

可以用一个二维数组来表示棋盘。例如,在五子棋游戏中,创建一个二维数组int[][] board,其中数组元素的值可以表示棋子的状态(0 表示没有棋子,1 表示黑棋,2 表示白棋)。

int[][] board = new int[15][15];
// 放置黑子
board[7][7] = 1;
// 放置白子
board[7][8] = 2;

通过检查数组中元素的状态和排列来判断游戏是否胜利。比如,检查是否有五子连珠的情况,可以通过遍历数组的行、列和对角线来实现。

3.2 角色扮演游戏(RPG)中的角色属性存储:

对于 RPG 游戏中的角色,用数组来存储角色的各种属性,如力量、敏捷、智力等。例如,创建一个int[] characterAttributes数组,其中characterAttributes[0]存储力量属性,characterAttributes[1]存储敏捷属性,characterAttributes[2]存储智力属性等。

int[] characterAttributes = new int[3];
characterAttributes[0] = 10; // 力量
characterAttributes[1] = 8;  // 敏捷
characterAttributes[2] = 12; // 智力

当角色升级或者获得装备时,可以通过修改数组中的元素来更新角色的属性。

3.3 图像处理应用

  1. 图像像素存储与处理:
    在简单的图像处理程序中,一幅灰度图像可以用一个二维数组来表示。例如,一个byte[][] imageArray数组,其中第一维表示图像的行,第二维表示图像的列,数组元素的值(范围从 0 - 255)表示像素的灰度值。
byte[][] imageArray = new byte[100][100];
// 假设给图像的左上角像素赋值
imageArray[0][0] = 128;

可以通过遍历数组来对图像进行各种处理,如灰度变换(例如将所有像素的灰度值增加一个固定值)、边缘检测等。例如,进行简单的灰度值增加操作:

for (int i = 0; i < 100; i++) {
    for (int j = 0; j < 100; j++) {
        imageArray[i][j] += 10;
        if (imageArray[i][j] > 255) {
            imageArray[i][j] = 255;
        }
    }
}

4. 用数组实现栈和队列的数据结构

4.1 用数组实现栈(Stack)

4.1.1 栈的基本概念

栈是一种后进先出(Last - In - First - Out,LIFO)的数据结构。可以把栈想象成一个只能在一端进行插入和删除操作的容器,这一端被称为栈顶。

4.1.2 数组实现栈的操作步骤
  1. 定义数组和栈顶指针
    首先,需要一个数组来存储栈中的元素,以及一个变量来记录栈顶元素的索引。例如,我们使用一个int类型的数组stackArray来存储整数元素,用一个变量top来表示栈顶索引。
private int[] stackArray;
private int top;
  1. 初始化栈
    在构造方法中,初始化数组的大小,并将栈顶指针初始化为 - 1,表示栈为空。
public Stack(int capacity) {
    stackArray = new int[capacity];
    top = -1;
}
  1. 入栈(Push)操作
    当要向栈中添加一个元素时,先将栈顶指针top加 1,然后将元素存储到stackArray[top]的位置。
public void push(int element) {
    if (top < stackArray.length - 1) {
        top++;
        stackArray[top] = element;
    } else {
        // 栈已满,可进行相应的处理,如抛出异常或扩容
        throw new StackOverflowError("Stack is full");
    }
}
  1. 出栈(Pop)操作
    从栈中取出元素时,先获取栈顶元素stackArray[top],然后将栈顶指针top减 1。
public int pop() {
    if (top >= 0) {
        int element = stackArray[top];
        top--;
        return element;
    } else {
        // 栈为空,可抛出异常
        throw new EmptyStackException();
    }
}
  1. 查看栈顶元素(Peek)操作
    仅返回栈顶元素的值,而不改变栈顶指针。
public int peek() {
    if (top >= 0) {
        return stackArray[top];
    } else {
        // 栈为空,可抛出异常
        throw new EmptyStackException();
    }
}
  1. 判断栈是否为空(isEmpty)操作
    当栈顶指针top为 - 1 时,栈为空。
public boolean isEmpty() {
    return top == -1;
}

4.2 用数组实现队列(Queue)

4.2.1 队列的基本概念

队列是一种先进先出(First - In - First - Out,FIFO)的数据结构。它有两个端点,一端用于插入元素(队尾),另一端用于删除元素(队头)。

4.2.2 数组实现队列的操作步骤
  1. 定义数组、队头和队尾指针
    同样需要一个数组来存储队列中的元素,用两个变量front和rear分别表示队头和队尾的索引。
private int[] queueArray;
private int front;
private int rear;
  1. 初始化队列
    在构造方法中,初始化数组的大小,并将队头和队尾指针初始化为 0,表示队列为空。
public Queue(int capacity) {
    queueArray = new int[capacity];
    front = 0;
    rear = 0;
}
  1. 入队(Enqueue)操作
    将元素添加到队尾。先将元素存储到queueArray[rear],然后将队尾指针rear加 1。如果队尾指针rear达到数组的长度,需要将其重置为 0(循环队列的概念)。
public void enqueue(int element) {
    if ((rear + 1) % queueArray.length!= front) {
        queueArray[rear] = element;
        rear = (rear + 1) % queueArray.length;
    } else {
        // 队列已满,可进行相应的处理,如抛出异常或扩容
        throw new IllegalStateException("Queue is full");
    }
}
  1. 出队(Dequeue)操作
    从队头取出元素。先获取队头元素queueArray[front],然后将队头指针front加 1。如果队头指针front达到数组的长度,也需要将其重置为 0。
public int dequeue() {
    if (front!= rear) {
        int element = queueArray[front];
        front = (front + 1) % queueArray.length;
        return element;
    } else {
        // 队列为空,可抛出异常
        throw new NoSuchElementException();
    }
}
  1. 查看队头元素(Peek)操作
    仅返回队头元素的值,而不改变队头和队尾指针。
public int peek() {
    if (front!= rear) {
        return queueArray[front];
    } else {
        // 队列为空,可抛出异常
        throw new NoSuchElementException();
    }
}
  1. 判断队列是否为空(isEmpty)操作
    当队头指针front和队尾指针rear相等时,队列为空。
public boolean isEmpty() {
    return front == rear;
}

5. 数组作为数据结构的优缺点

5.1 优点

  1. 简单直观
    数组的概念非常容易理解,它是一种线性的数据结构,将相同类型的数据元素按照顺序存储在一块连续的内存空间中。例如,int[] numbers = {1, 2, 3, 4, 5};这样的数组定义方式非常直观,开发人员很容易理解数组中存储的数据以及它们的顺序。
  2. 访问效率高
    通过索引可以快速地访问数组中的任意元素。由于数组元素在内存中是连续存储的,计算机可以根据数组的起始地址和元素类型的大小,通过简单的计算就能快速定位到指定索引的元素。例如,对于一个int类型的数组(int类型通常占 4 个字节),如果数组的起始地址是0x1000,要访问索引为3的元素,计算机可以直接计算出该元素的内存地址为0x1000 + 3 * 4 = 0x100C,这种随机访问的时间复杂度是。这使得数组在需要频繁访问元素的场景下(如查找特定位置的元素)非常高效。
  3. 存储密度高
    因为数组存储的是同一种数据类型,所以在内存中可以紧密排列。这样可以有效地利用内存空间,特别是对于基本数据类型的数组,不会像一些复杂的数据结构那样存在额外的指针或其他开销来维护数据之间的关系。例如,存储 100 个int类型的数据,只需要连续的100 * sizeof(int)字节的内存空间(假设sizeof(int)为 4 字节,那么总共需要 400 字节)。
  4. 支持随机访问和顺序访问
    除了通过索引进行随机访问外,数组也很适合顺序访问。可以使用循环从数组的第一个元素开始,依次访问每个元素,这种顺序访问在很多算法和应用场景中都非常有用。例如,在计算数组中所有元素的总和时,使用循环顺序访问数组元素并累加,代码简洁高效。

5.2 缺点

  1. 大小固定
    一旦数组被创建,它的大小就固定了。例如,int[] fixedArray = new int[10];这个数组的长度就只能是 10,无法动态地增加或减少其容量。如果在程序运行过程中需要存储更多的元素,可能会导致数组溢出的问题;而如果预先分配的空间过大,又会造成内存的浪费。
  2. 插入和删除操作复杂(非尾部操作)
    在数组中间插入或删除一个元素时,需要移动大量的其他元素。例如,在一个有序数组{1, 2, 3, 4, 5}中,如果要在索引为2的位置插入一个元素6,需要将索引为2及以后的元素(3、4、5)都向后移动一位,为新元素腾出空间,这个操作的时间复杂度是(其中n是数组中元素的数量)。同样,删除一个非尾部元素时,也需要移动后面的元素来填补空缺,这在元素数量较多的情况下会导致性能下降。
  3. 缺乏动态性
    数组不具备像链表等数据结构那样的动态灵活性。例如,链表可以很容易地在节点之间建立或断开连接,实现动态的插入和删除操作,而数组很难适应数据频繁变化的情况。而且,对于一些需要频繁进行数据结构调整的应用场景,数组可能无法满足需求,需要借助其他更灵活的数据结构来实现。

7. 后记

在实际的 Java 编程中,数组是非常基础且重要的结构,广泛应用于数据存储、算法实现等多个领域。

本文完。
码字不易,宝贵经验分享不易,请各位支持原创,转载注明出处,多多关注作者,家人们的点赞和关注是我笔耕不辍的动力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值