数组:编程世界的万能收纳架,你真的会用吗?
想象一下,你有一个药盒,里面有7个小格子,分别放着周一到周日的药。每天早上,你只需要打开对应日期的格子取药------这,就是数组在现实生活中的完美体现!
数组就像是我们生活中的各种收纳工具:
- 🗃️ 药盒 → 一维数组
- 🎒 多层饭盒 → 二维数组
- 📚 书架 → 三维数组
- 🏢 公寓楼 → 多维数组
今天,就让我带你彻底搞懂这个看似简单、实则暗藏玄机的数据结构!
第一章:数组到底是什么?
1.1 用大白话解释数组
数组就是一群"数据类型相同、住址相邻"的数据元素的集合。
把内存想象成一条大街,数组就是街上的一排连号公寓:
css
内存地址: 1001 1002 1003 1004 1005
住户数据:[ A ][ B ][ C ][ D ][ E ]
房间号: 0 1 2 3 4
三个关键特征:
- 📍 住址固定:每个元素有固定的"门牌号"(索引)
- 👯 同类聚居:所有元素必须是同一数据类型
- 🏘️ 紧密相邻:元素在内存中紧密排列,没有空隙
1.2 为什么需要数组?
假设我们要记录5个学生的成绩:
笨方法:
java
int score1 = 90;
int score2 = 85;
int score3 = 92;
int score4 = 78;
int score5 = 88;
// 要计算平均分得写:double avg = (score1 + score2 + ... + score5) / 5.0;
聪明方法(用数组):
java
int[] scores = {90, 85, 92, 78, 88};
// 计算平均分:
int sum = 0;
for(int i = 0; i < scores.length; i++) {
sum += scores[i];
}
double avg = sum / 5.0;
看到差别了吗?数组让我们的代码更简洁、更易扩展!
第二章:静态数组 vs 动态数组
2.1 静态数组
举个例子:就像健身房租的储物柜,大小固定,多了放不下,少了空间浪费。
java
// 创建一个能放5本书的书架(静态数组)
String[] bookshelf = new String[5];
// 往书架上放书
bookshelf[0] = "Java编程思想";
bookshelf[1] = "数据结构与算法";
bookshelf[2] = "设计模式";
bookshelf[3] = "计算机网络";
bookshelf[4] = "操作系统";
// 悲剧:想放第6本书?放不下了!
// bookshelf[5] = "编译原理"; // 这会报错!
静态数组原理图:
arduino
静态数组就像固定格子的储物柜:
┌─────────┬─────────┬─────────┬─────────┬─────────┐
│ 格子0 │ 格子1 │ 格子2 │ 格子3 │ 格子4 │
│ "Java" │"数据结构"│"设计模式"│"计算机网络"│"操作系统"│
└─────────┴─────────┴─────────┴─────────┴─────────┘
大小固定:5个格子,无法增加或减少
2.2 动态数组"
举个例子:就像哈利波特的魔法背包,东西多了自动变大,永远装得下!
java
// Java中的ArrayList就是动态数组
import java.util.ArrayList;
public class MagicBackpack {
public static void main(String[] args) {
// 创建一个空的魔法背包
ArrayList<String> backpack = new ArrayList<>();
System.out.println("初始背包容量: " + backpack.size());
// 往背包里放东西,不用担心容量
backpack.add("魔法杖");
backpack.add("隐身衣");
backpack.add("飞行扫帚");
backpack.add("时间转换器");
backpack.add("复活石");
System.out.println("放了5件物品后容量: " + backpack.size());
// 再放一件,背包会自动扩容!
backpack.add("厄里斯魔镜");
System.out.println("放了6件物品后容量: " + backpack.size());
}
}
动态数组扩容流程图:
scss
┌─────────────────────────────────────────────┐
│ 动态数组扩容过程 │
├─────────────────────────────────────────────┤
│ 1. 背包已满,还想放新物品 │
│ ↓ │
│ 2. 召唤一个更大的新背包(通常是1.5-2倍大) │
│ ↓ │
│ 3. 把旧背包所有物品搬到新背包 │
│ ↓ │
│ 4. 扔掉旧背包,使用新背包 │
│ ↓ │
│ 5. 把新物品放进新背包 │
└─────────────────────────────────────────────┘
实际扩容代码模拟:
java
public class DynamicArrayDemo {
private int[] data; // 存储数据的数组
private int size; // 当前元素个数
private int capacity; // 总容量
public DynamicArrayDemo() {
capacity = 3; // 初始容量3
data = new int[capacity];
size = 0;
}
// 添加元素,自动扩容
public void add(int value) {
// 如果背包满了,就扩容
if (size == capacity) {
System.out.println("⚠️ 背包已满,开始扩容...");
resize(capacity * 2); // 容量翻倍
}
data[size] = value;
size++;
System.out.println("✅ 添加元素: " + value + ", 当前大小: " + size);
}
// 扩容方法
private void resize(int newCapacity) {
System.out.println("🔄 从容量 " + capacity + " 扩容到 " + newCapacity);
int[] newData = new int[newCapacity]; // 创建新背包
// 把旧背包的东西搬到新背包
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data = newData; // 换上新背包
capacity = newCapacity;
System.out.println("🎉 扩容完成!");
}
}
第三章:揭秘数组操作效率
3.1 读取元素:为什么这么快?
举个例子:我们生活中常见的场景,就像你知道朋友住在3号楼201房间,直接去敲门就行,不用从1号楼开始找。
java
int[] apartmentBuilding = {101, 102, 103, 104, 105};
// 直接访问3号房间(索引为2)
int room3 = apartmentBuilding[2]; // 瞬间拿到103!
// 计算机怎么做到的?
// 内存地址 = 起始地址 + 索引 × 元素大小
// 假设起始地址是1000,每个int占4字节:
// 房间3的地址 = 1000 + 2 × 4 = 1008
// 直接去1008地址取数据,一步到位!
随机访问原理图:
ini
内存街道:
地址: 1000 1004 1008 1012 1016
数据: [ 101 ][ 102 ][ 103 ][ 104 ][ 105 ]
索引: 0 1 2 3 4
要找103号(索引2):
1. 知道整条街起点:1000
2. 知道每个房子大小:4字节
3. 计算:1000 + 2 × 4 = 1008
4. 直接去1008敲门 → 拿到103!
时间复杂度:O(1) - 恒定时间,与数组大小无关
3.2 插入元素:为什么这么麻烦?
生活比喻:就像在排队买奶茶时,有人要插队到中间位置,后面所有人都得往后挪一步。
java
public class ArrayInsertExample {
public static void main(String[] args) {
// 原数组:5个人的队伍
String[] queue = {"小明", "小红", "小刚", "小丽", null};
System.out.println("原队伍: " + Arrays.toString(queue));
// 小华要插队到第2个位置(索引1)
int insertPosition = 1;
String newPerson = "小华";
// 插入过程:后面的人都要往后挪
System.out.println("🚶 开始挪动位置...");
for (int i = queue.length - 1; i > insertPosition; i--) {
queue[i] = queue[i - 1]; // 每个人往后挪一位
System.out.println("第" + (i-1) + "位挪到第" + i + "位");
}
// 空出位置后,新的人插入
queue[insertPosition] = newPerson;
System.out.println("✅ " + newPerson + "插入到位置" + insertPosition);
System.out.println("新队伍: " + Arrays.toString(queue));
}
}
插入操作流程图:
css
┌─────────────────────────────────────────────┐
│ 数组插入元素过程 │
├─────────────────────────────────────────────┤
│ 原数组:[A, B, C, D, E, 空] │
│ 要在索引1位置插入X │
│ │
│ 步骤1:从后往前,逐个后移 │
│ E → 空位, D → E的位置, C → D的位置... │
│ │
│ 步骤2:空出目标位置 │
│ [A, 空, B, C, D, E] │
│ │
│ 步骤3:插入新元素 │
│ [A, X, B, C, D, E] │
└─────────────────────────────────────────────┘
插入时间复杂度分析:
- 🏆 最佳情况 :在末尾插入 → O(1)
- 不用移动任何元素,直接放最后就行
- 😊 平均情况 :在中间插入 → O(n)
- 平均需要移动 n/2 个元素
- 😭 最坏情况 :在开头插入 → O(n)
- 需要移动所有 n 个元素
3.3 删除元素:同样麻烦的搬家过程
java
public class ArrayDeleteExample {
public static void main(String[] args) {
// 原数组:5个人的队伍
String[] queue = {"小明", "小红", "小刚", "小丽", "小华"};
System.out.println("原队伍: " + Arrays.toString(queue));
// 第2个人(索引1)要离开队伍
int deletePosition = 1;
System.out.println("❌ 位置" + deletePosition + "的" +
queue[deletePosition] + "要离开");
// 删除过程:后面的人往前补位
System.out.println("🚶 开始补位...");
for (int i = deletePosition; i < queue.length - 1; i++) {
queue[i] = queue[i + 1]; // 后面的人往前补
System.out.println("第" + (i+1) + "位补到第" + i + "位");
}
// 最后一个位置置空
queue[queue.length - 1] = null;
System.out.println("✅ 删除完成");
System.out.println("新队伍: " + Arrays.toString(queue));
}
}
3.4 数组操作效率总结表
| 操作 | 时间复杂度 | 形象比喻 | 效率评价 |
|---|---|---|---|
| 读取 | O(1) | 按门牌号直接找人 | ⭐⭐⭐⭐⭐ 极快 |
| 搜索 | O(n) | 挨家挨户敲门找 | ⭐⭐☆☆☆ 较慢 |
| 插入 | O(n) | 排队中间插队 | ⭐⭐☆☆☆ 较慢 |
| 删除 | O(n) | 排队中间离开 | ⭐⭐☆☆☆ 较慢 |
第四章:多维数组 - 从线到面
4.1 二维数组:数据的"Excel表格"
举个生活中的场景来形容二维数组:
- 一维数组 → 一条街道的门牌号
- 二维数组 → 一个小区的楼号+单元号
- 三维数组 → 一个城市的区+街道+门牌号
java
// 用二维数组表示棋盘游戏
public class ChessBoard {
public static void main(String[] args) {
// 创建8×8的国际象棋棋盘
String[][] chessBoard = new String[8][8];
// 初始化棋盘 - 空棋盘用"·"表示
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
chessBoard[row][col] = "·";
}
}
// 摆放棋子
// 白方棋子
chessBoard[0] = new String[]{"♜", "♞", "♝", "♛", "♚", "♝", "♞", "♜"};
chessBoard[1] = new String[]{"♟", "♟", "♟", "♟", "♟", "♟", "♟", "♟"};
// 黑方棋子
chessBoard[6] = new String[]{"♙", "♙", "♙", "♙", "♙", "♙", "♙", "♙"};
chessBoard[7] = new String[]{"♖", "♘", "♗", "♕", "♔", "♗", "♘", "♖"};
// 打印棋盘
System.out.println(" a b c d e f g h");
System.out.println(" ┌─┬─┬─┬─┬─┬─┬─┬─┐");
for (int row = 0; row < 8; row++) {
System.out.print((8 - row) + " │");
for (int col = 0; col < 8; col++) {
System.out.print(chessBoard[row][col] + "│");
}
System.out.println(" " + (8 - row));
if (row < 7) {
System.out.println(" ├─┼─┼─┼─┼─┼─┼─┼─┤");
}
}
System.out.println(" └─┴─┴─┴─┴─┴─┴─┴─┘");
System.out.println(" a b c d e f g h");
}
}
4.2 多维数组的内存存储
重要:虽然我们觉得二维数组是表格,但在内存中,它仍然是一维连续存储的!
java
// 二维数组:3行4列的表格
int[][] classroom = {
{1, 2, 3, 4}, // 第一排
{5, 6, 7, 8}, // 第二排
{9, 10, 11, 12} // 第三排
};
// 在内存中的实际存储:
// 地址: 1000 1004 1008 1012 1016 1020 1024 1028 1032 1036 1040 1044
// 数据: [ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][10][11][12]
内存寻址公式:
java
// 访问classroom[i][j]的地址计算:
// 地址 = 基地址 + (i × 列数 + j) × 元素大小
// 例子:访问classroom[1][2](值为7)
// 假设基地址=1000,列数=4,元素大小=4字节
// 地址 = 1000 + (1×4 + 2)×4
// = 1000 + 6×4
// = 1000 + 24 = 1024
// 去1024地址取数据 → 得到7!
多维数组存储原理图:
css
我们眼中的二维数组:
┌─────┬─────┬─────┬─────┐
│ [0][0] │ [0][1] │ [0][2] │ [0][3] │ ← 第0行
├─────┼─────┼─────┼─────┤
│ [1][0] │ [1][1] │ [1][2] │ [1][3] │ ← 第1行
├─────┼─────┼─────┼─────┤
│ [2][0] │ [2][1] │ [2][2] │ [2][3] │ ← 第2行
└─────┴─────┴─────┴─────┘
内存中的真实存储(行优先):
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
│00│01│02│03│10│11│12│13│20│21│22│23│
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
第五章:数组的实战应用
5.1 应用一:学生成绩管理系统
java
import java.util.Arrays;
public class StudentGradeSystem {
public static void main(String[] args) {
// 用二维数组存储3个学生的4门课成绩
// 行:学生,列:课程
int[][] grades = {
{85, 92, 78, 90}, // 学生1:数学,语文,英语,物理
{76, 88, 95, 82}, // 学生2
{92, 79, 85, 88} // 学生3
};
String[] students = {"张三", "李四", "王五"};
String[] subjects = {"数学", "语文", "英语", "物理"};
System.out.println("🎓 学生成绩统计系统");
System.out.println("==================");
// 1. 计算每个学生的平均分
System.out.println("\n📊 学生平均分:");
for (int i = 0; i < grades.length; i++) {
int sum = 0;
for (int j = 0; j < grades[i].length; j++) {
sum += grades[i][j];
}
double average = (double) sum / grades[i].length;
System.out.printf("%s: %.2f分\n", students[i], average);
}
// 2. 计算每门课的平均分
System.out.println("\n📈 科目平均分:");
for (int j = 0; j < grades[0].length; j++) {
int sum = 0;
for (int i = 0; i < grades.length; i++) {
sum += grades[i][j];
}
double average = (double) sum / grades.length;
System.out.printf("%s: %.2f分\n", subjects[j], average);
}
// 3. 找出每门课的最高分
System.out.println("\n🏆 单科最高分:");
for (int j = 0; j < grades[0].length; j++) {
int maxScore = 0;
String topStudent = "";
for (int i = 0; i < grades.length; i++) {
if (grades[i][j] > maxScore) {
maxScore = grades[i][j];
topStudent = students[i];
}
}
System.out.printf("%s: %s (%d分)\n",
subjects[j], topStudent, maxScore);
}
}
}
5.2 应用二:图像处理 - 像素矩阵
java
public class ImageProcessor {
// 用二维数组表示黑白图片
// 0=纯黑, 255=纯白
public static void main(String[] args) {
// 5×5像素的简单图像(一个笑脸)
int[][] image = createSmileyFace();
System.out.println("😊 原图像(笑脸):");
printImage(image);
// 图像处理1:反色效果
int[][] inverted = invertImage(image);
System.out.println("\n🔄 反色效果:");
printImage(inverted);
// 图像处理2:模糊效果
int[][] blurred = blurImage(image);
System.out.println("\n💨 模糊效果:");
printImage(blurred);
}
// 创建笑脸图像
public static int[][] createSmileyFace() {
int[][] img = new int[5][5];
// 初始化全白
for (int i = 0; i < 5; i++) {
Arrays.fill(img[i], 255);
}
// 画笑脸
img[1][1] = 0; // 左眼
img[1][3] = 0; // 右眼
img[3][1] = 0; // 嘴左
img[3][2] = 0; // 嘴中
img[3][3] = 0; // 嘴右
return img;
}
// 图像反色:黑变白,白变黑
public static int[][] invertImage(int[][] original) {
int height = original.length;
int width = original[0].length;
int[][] result = new int[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
result[i][j] = 255 - original[i][j];
}
}
return result;
}
// 简单模糊:每个像素取周围像素的平均值
public static int[][] blurImage(int[][] original) {
int height = original.length;
int width = original[0].length;
int[][] result = new int[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int sum = 0, count = 0;
// 检查周围的3×3区域
for (int di = -1; di <= 1; di++) {
for (int dj = -1; dj <= 1; dj++) {
int ni = i + di, nj = j + dj;
if (ni >= 0 && ni < height && nj >= 0 && nj < width) {
sum += original[ni][nj];
count++;
}
}
}
result[i][j] = sum / count; // 取平均值
}
}
return result;
}
// 打印图像
public static void printImage(int[][] image) {
for (int[] row : image) {
for (int pixel : row) {
// 用不同字符表示灰度
if (pixel == 0) System.out.print("■ "); // 纯黑
else if (pixel < 100) System.out.print("▒ "); // 深灰
else if (pixel < 200) System.out.print("░ "); // 浅灰
else System.out.print("□ "); // 纯白
}
System.out.println();
}
}
}
5.3 应用三:游戏地图
java
public class GameMapSystem {
// 定义地图元素类型
static final int EMPTY = 0; // 空地
static final int WALL = 1; // 墙
static final int TREASURE = 2; // 宝藏
static final int PLAYER = 3; // 玩家
static final int ENEMY = 4; // 敌人
static final int DOOR = 5; // 门
public static void main(String[] args) {
// 创建10×10的游戏地图
int[][] gameMap = createGameMap();
System.out.println("🎮 游戏地图生成完毕!");
printGameMap(gameMap);
// 移动玩家
System.out.println("\n🎯 玩家移动中...");
movePlayer(gameMap, 2, 1); // 向右移动
printGameMap(gameMap);
}
// 创建游戏地图
public static int[][] createGameMap() {
int[][] map = new int[10][10];
// 初始化:四周是墙,中间是空地
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (i == 0 || i == 9 || j == 0 || j == 9) {
map[i][j] = WALL; // 边界墙
} else {
map[i][j] = EMPTY; // 内部空地
}
}
}
// 放置障碍物
map[2][2] = WALL; map[2][3] = WALL;
map[5][5] = WALL; map[5][6] = WALL;
map[7][3] = WALL; map[7][4] = WALL;
// 放置宝藏
map[1][7] = TREASURE;
map[8][2] = TREASURE;
map[6][8] = TREASURE;
// 放置敌人
map[3][7] = ENEMY;
map[8][6] = ENEMY;
// 放置门
map[9][5] = DOOR;
// 放置玩家(起始位置)
map[1][1] = PLAYER;
return map;
}
// 移动玩家
public static void movePlayer(int[][] map, int dx, int dy) {
// 找到玩家当前位置
int playerX = -1, playerY = -1;
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) {
if (map[i][j] == PLAYER) {
playerX = i;
playerY = j;
break;
}
}
}
// 计算新位置
int newX = playerX + dx;
int newY = playerY + dy;
// 检查是否可以移动
if (newX >= 0 && newX < map.length &&
newY >= 0 && newY < map[0].length) {
if (map[newX][newY] == EMPTY) {
// 移动玩家
map[playerX][playerY] = EMPTY; // 原位置清空
map[newX][newY] = PLAYER; // 新位置放置玩家
System.out.println("✅ 移动成功!");
} else if (map[newX][newY] == TREASURE) {
System.out.println("💰 找到宝藏!游戏胜利!");
map[playerX][playerY] = EMPTY;
map[newX][newY] = PLAYER;
} else if (map[newX][newY] == WALL) {
System.out.println("🚫 撞墙了!无法移动");
} else if (map[newX][newY] == ENEMY) {
System.out.println("💀 遇到敌人!游戏结束");
} else if (map[newX][newY] == DOOR) {
System.out.println("🚪 找到出口!游戏通关!");
}
} else {
System.out.println("🚫 超出地图边界!");
}
}
// 打印游戏地图
public static void printGameMap(int[][] map) {
char[] symbols = {' ', '█', '★', 'P', 'E', 'D'};
String[] names = {"空地", "墙", "宝藏", "玩家", "敌人", "门"};
System.out.println("\n地图图例:");
for (int i = 0; i < symbols.length; i++) {
System.out.println(" " + symbols[i] + " = " + names[i]);
}
System.out.println("\n当前地图:");
System.out.println("┌───────────────────┐");
for (int i = 0; i < map.length; i++) {
System.out.print("│ ");
for (int j = 0; j < map[i].length; j++) {
System.out.print(symbols[map[i][j]] + " ");
}
System.out.println("│");
}
System.out.println("└───────────────────┘");
}
}
第六章:数组使用技巧与最佳实践
6.1 数组遍历的四种姿势
java
import java.util.Arrays;
public class ArrayTraversalStyles {
public static void main(String[] args) {
String[] fruits = {"苹果", "香蕉", "橙子", "葡萄", "芒果"};
System.out.println("🍎 水果数组: " + Arrays.toString(fruits));
// 姿势1:传统for循环 - 最灵活
System.out.println("\n1. 传统for循环(可控制索引):");
for (int i = 0; i < fruits.length; i++) {
System.out.println(" 索引 " + i + ": " + fruits[i]);
}
// 姿势2:增强for循环 - 最简洁
System.out.println("\n2. 增强for循环(只读遍历):");
for (String fruit : fruits) {
System.out.println(" 水果: " + fruit);
}
// 姿势3:while循环 - 灵活控制
System.out.println("\n3. while循环(手动控制):");
int index = 0;
while (index < fruits.length) {
System.out.println(" 第" + (index+1) + "个: " + fruits[index]);
index++;
}
// 姿势4:Stream API - 函数式风格
System.out.println("\n4. Stream API(现代风格):");
Arrays.stream(fruits)
.forEach(fruit -> System.out.println(" 🍓 " + fruit));
}
}
6.2 数组常用方法
java
import java.util.Arrays;
import java.util.Collections;
public class ArrayUtilsDemo {
public static void main(String[] args) {
Integer[] numbers = {3, 1, 4, 1, 5, 9, 2, 6};
System.out.println("原数组: " + Arrays.toString(numbers));
// 1. 排序
Arrays.sort(numbers);
System.out.println("排序后: " + Arrays.toString(numbers));
// 2. 反转排序
Arrays.sort(numbers, Collections.reverseOrder());
System.out.println("降序后: " + Arrays.toString(numbers));
// 3. 二分查找(必须先排序)
Arrays.sort(numbers);
int index = Arrays.binarySearch(numbers, 5);
System.out.println("数字5的位置: " + index);
// 4. 数组复制
Integer[] copy = Arrays.copyOf(numbers, numbers.length);
System.out.println("复制数组: " + Arrays.toString(copy));
// 5. 数组填充
Integer[] filled = new Integer[5];
Arrays.fill(filled, 42);
System.out.println("填充数组: " + Arrays.toString(filled));
// 6. 数组比较
System.out.println("数组相等: " + Arrays.equals(numbers, copy));
}
}
第七章:数组的优缺点总结
🎯 数组的优点:
- ⚡ 访问速度极快 - 随机访问时间复杂度O(1)
- 💾 内存效率高 - 只存储数据,几乎没有额外开销
- 🔄 缓存友好 - 连续内存,预加载效果好
- 🔧 实现简单 - 所有编程语言原生支持
⚠️ 数组的缺点:
- 📏 大小固定 - 创建后难以调整容量(静态数组)
- 🚶 插入删除慢 - 平均需要移动O(n)个元素
- 🏠 内存要求高 - 需要连续的较大内存空间
- 🎯 类型单一 - 只能存储相同类型数据
📊 选择数组的场景:
✅ 适合用数组的情况:
- 数据量已知或变化不大
- 需要频繁随机访问
- 对性能要求较高
- 实现简单的多维数据结构
❌ 不适合用数组的情况:
- 数据量变化很大
- 需要频繁插入删除
- 内存碎片严重
- 需要存储不同类型数据
结语:数组是数据结构的基础,更是一门艺术
到这里相信你已经对数组有了全新的认识。数组就像编程世界里的乐高积木,看似简单,却能搭建出各种复杂的数据结构:
- 链表 = 数组 + 指针
- 栈 = 数组 + 后进先出规则
- 队列 = 数组 + 先进先出规则
- 哈希表 = 数组 + 哈希函数
记住:真正的高手不是会用复杂的数据结构,而是懂得在合适的地方使用最简单的数据结构。
觉得有收获吗?来个一键三连吧!欢迎在评论区分享交流,我们一起进步!