📊 Mảng Đa Chiều - Multi-Dimensional Arrays
Chào mừng đến với bài học về Multi-Dimensional Arrays - cách quản lý bảng 2 chiều trong Café!
🎯 Món Ăn Hôm Nay
Tưởng tượng bạn đang quản lý quán cà phê:
- Bảng giá theo tuần → Mảng 2 chiều (7 ngày × 5 món)
- Sơ đồ bàn → Mảng 2 chiều (hàng × cột)
- Quản lý dữ liệu dạng bảng → Hiệu quả hơn
Đó chính là Multi-Dimensional Arrays - mảng của mảng!
📊 Multi-Dimensional Array Là Gì?
Mảng 2 chiều = Bảng có hàng và cột (mảng của mảng)
// Bảng giá: 3 ngày × 3 món
int[][] bangGia = {
{45000, 50000, 55000}, // Ngày 1
{46000, 51000, 56000}, // Ngày 2
{45000, 49000, 54000} // Ngày 3
};
// Truy cập: bangGia[hàng][cột]
int gia = bangGia[0][1]; // Hàng 0, cột 1 → 50000
☕ Ẩn Dụ Café:
- Mảng 2D = Bảng menu trên tường
- Hàng = Ngày trong tuần
- Cột = Các món đồ uống
- Phần tử = Giá của món tại ngày cụ thể
🔢 Index Mảng 2D
int[][] data = {
{10, 20, 30},
{40, 50, 60}
};
// data[hàng][cột]
data[0][0] // 10
data[0][1] // 20
data[1][2] // 60
👨🍳 Câu Chuyện Trong Quán
Tình huống 1: Sơ Đồ Bàn
public class SoDoban {
public static void main(String[] args) {
// 0 = Trống, 1 = Có khách
int[][] soDoBan = {
{1, 0, 1}, // Hàng 1
{0, 1, 0}, // Hàng 2
{1, 1, 0} // Hàng 3
};
System.out.println("🪑 SƠ ĐỒ BÀN:\n");
for (int hang = 0; hang < soDoBan.length; hang++) {
System.out.print("Hàng " + (hang + 1) + ": ");
for (int cot = 0; cot < soDoBan[hang].length; cot++) {
if (soDoBan[hang][cot] == 1) {
System.out.print("🔴 "); // Có khách
} else {
System.out.print("⚪ "); // Trống
}
}
System.out.println();
}
}
}
Output:
🪑 SƠ ĐỒ BÀN:
Hàng 1: 🔴 ⚪ 🔴
Hàng 2: ⚪ 🔴 ⚪
Hàng 3: 🔴 🔴 ⚪
Tình huống 2: Doanh Thu Tuần
public class DoanhThuTuan {
public static void main(String[] args) {
String[] ngay = {"T2", "T3", "T4", "T5", "T6", "T7", "CN"};
String[] buoi = {"Sáng", "Trưa", "Tối"};
int[][] doanhThu = {
{50000, 80000, 100000}, // T2
{55000, 85000, 110000}, // T3
{60000, 90000, 120000}, // T4
{58000, 88000, 115000}, // T5
{65000, 95000, 130000}, // T6
{120000, 150000, 180000}, // T7
{130000, 160000, 190000} // CN
};
System.out.println("📊 DOANH THU TUẦN:\n");
System.out.printf("%-5s", "");
for (String b : buoi) {
System.out.printf("%12s", b);
}
System.out.println("\n" + "━".repeat(41));
for (int i = 0; i < ngay.length; i++) {
System.out.printf("%-5s", ngay[i]);
for (int j = 0; j < buoi.length; j++) {
System.out.printf("%,12d", doanhThu[i][j]);
}
System.out.println();
}
}
}
Output:
📊 DOANH THU TUẦN:
Sáng Trưa Tối
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
T2 50,000 80,000 100,000
T3 55,000 85,000 110,000
T4 60,000 90,000 120,000
T5 58,000 88,000 115,000
T6 65,000 95,000 130,000
T7 120,000 150,000 180,000
CN 130,000 160,000 190,000
📝 Công Thức Nấu (Code Examples)
Ví Dụ 1: Khai Báo Mảng 2D
public class KhaiBaoMang2D {
public static void main(String[] args) {
// Cách 1: Khởi tạo trực tiếp
int[][] gia1 = {
{45000, 50000},
{55000, 60000}
};
// Cách 2: Khai báo rồi gán
int[][] gia2 = new int[2][2];
gia2[0][0] = 45000;
gia2[0][1] = 50000;
gia2[1][0] = 55000;
gia2[1][1] = 60000;
// Cách 3: Mảng jagged (hàng có độ dài khác nhau)
int[][] gia3 = new int[2][];
gia3[0] = new int[]{45000, 50000, 55000}; // 3 phần tử
gia3[1] = new int[]{60000, 65000}; // 2 phần tử
System.out.println("Giá [0][1]: " + gia1[0][1]);
}
}
Ví Dụ 2: Duyệt Mảng 2D
public class DuyetMang2D {
public static void main(String[] args) {
String[][] menu = {
{"Espresso", "Latte", "Mocha"},
{"Cappuccino", "Americano", "Macchiato"}
};
System.out.println("☕ MENU 2 TẦNG:\n");
// Duyệt với for loop
for (int i = 0; i < menu.length; i++) {
System.out.println("Tầng " + (i + 1) + ":");
for (int j = 0; j < menu[i].length; j++) {
System.out.println(" " + (j + 1) + ". " + menu[i][j]);
}
System.out.println();
}
// Duyệt với for-each
System.out.println("FOR-EACH:\n");
for (String[] tang : menu) {
for (String mon : tang) {
System.out.print(mon + " ");
}
System.out.println();
}
}
}
Ví Dụ 3: Tính Tổng Mảng 2D
public class TinhTongMang2D {
public static void main(String[] args) {
int[][] doanhThu = {
{100000, 150000, 200000}, // Tuần 1
{120000, 160000, 210000}, // Tuần 2
{110000, 155000, 205000}, // Tuần 3
{130000, 170000, 220000} // Tuần 4
};
System.out.println("📊 DOANH THU THÁNG:\n");
int tongThang = 0;
for (int tuan = 0; tuan < doanhThu.length; tuan++) {
int tongTuan = 0;
System.out.print("Tuần " + (tuan + 1) + ": ");
for (int ngay = 0; ngay < doanhThu[tuan].length; ngay++) {
tongTuan += doanhThu[tuan][ngay];
}
System.out.printf("%,d VND%n", tongTuan);
tongThang += tongTuan;
}
System.out.println("━".repeat(30));
System.out.printf("TỔNG THÁNG: %,d VND%n", tongThang);
}
}
Output:
📊 DOANH THU THÁNG:
Tuần 1: 450,000 VND
Tuần 2: 490,000 VND
Tuần 3: 470,000 VND
Tuần 4: 520,000 VND
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
TỔNG THÁNG: 1,930,000 VND
Ví Dụ 4: Tìm Giá Trị Lớn Nhất
public class TimMaxMang2D {
public static void main(String[] args) {
int[][] soBan = {
{10, 15, 20}, // Espresso, Latte, Mocha
{25, 30, 18}, // Sáng, Trưa, Tối
{12, 22, 28}
};
String[] mon = {"Espresso", "Latte", "Mocha"};
String[] buoi = {"Sáng", "Trưa", "Tối"};
int max = soBan[0][0];
int maxHang = 0, maxCot = 0;
for (int i = 0; i < soBan.length; i++) {
for (int j = 0; j < soBan[i].length; j++) {
if (soBan[i][j] > max) {
max = soBan[i][j];
maxHang = i;
maxCot = j;
}
}
}
System.out.println("🏆 BÁN CHẠY NHẤT:");
System.out.println("Số lượng: " + max + " ly");
System.out.println("Buổi: " + buoi[maxHang]);
System.out.println("Món: " + mon[maxCot]);
}
}
Ví Dụ 5: Ma Trận Vuông (NxN)
public class MaTranVuong {
public static void main(String[] args) {
int[][] maTran = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
System.out.println("📐 MA TRẬN 3×3:\n");
// In ma trận
for (int i = 0; i < maTran.length; i++) {
for (int j = 0; j < maTran[i].length; j++) {
System.out.printf("%3d", maTran[i][j]);
}
System.out.println();
}
// Tính tổng đường chéo chính
int tongCheoChinh = 0;
for (int i = 0; i < maTran.length; i++) {
tongCheoChinh += maTran[i][i]; // [0][0], [1][1], [2][2]
}
System.out.println("\nTổng đường chéo chính: " + tongCheoChinh);
}
}
Output:
📐 MA TRẬN 3×3:
1 2 3
4 5 6
7 8 9
Tổng đường chéo chính: 15
Ví Dụ 6: Mảng Jagged (Không Đều)
public class MangJagged {
public static void main(String[] args) {
// Mỗi hàng có số cột khác nhau
String[][] khuVuc = {
{"Bàn 1", "Bàn 2"}, // Khu A: 2 bàn
{"Bàn 3", "Bàn 4", "Bàn 5"}, // Khu B: 3 bàn
{"Bàn 6", "Bàn 7", "Bàn 8", "Bàn 9"} // Khu C: 4 bàn
};
System.out.println("🏢 SƠ ĐỒ KHU VỰC:\n");
for (int i = 0; i < khuVuc.length; i++) {
System.out.print("Khu " + (char)('A' + i) + ": ");
for (int j = 0; j < khuVuc[i].length; j++) {
System.out.print(khuVuc[i][j]);
if (j < khuVuc[i].length - 1) {
System.out.print(", ");
}
}
System.out.println();
}
}
}
Output:
🏢 SƠ ĐỒ KHU VỰC:
Khu A: Bàn 1, Bàn 2
Khu B: Bàn 3, Bàn 4, Bàn 5
Khu C: Bàn 6, Bàn 7, Bàn 8, Bàn 9
🔥 Thực Hành Trong Quán
Bài Tập 1: Bảng Giá Theo Size
public class BangGiaSize {
public static void main(String[] args) {
String[] mon = {"Espresso", "Latte", "Mocha"};
String[] size = {"S", "M", "L"};
int[][] gia = {
{35000, 40000, 45000}, // Espresso
{40000, 45000, 50000}, // Latte
{45000, 50000, 55000} // Mocha
};
System.out.println("💰 BẢNG GIÁ THEO SIZE:\n");
System.out.printf("%-12s", "");
for (String s : size) {
System.out.printf("%10s", s);
}
System.out.println("\n" + "━".repeat(42));
for (int i = 0; i < mon.length; i++) {
System.out.printf("%-12s", mon[i]);
for (int j = 0; j < size.length; j++) {
System.out.printf("%,10d", gia[i][j]);
}
System.out.println();
}
}
}
Output:
💰 BẢNG GIÁ THEO SIZE:
S M L
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Espresso 35,000 40,000 45,000
Latte 40,000 45,000 50,000
Mocha 45,000 50,000 55,000
Bài Tập 2: Quản Lý Kho Theo Tuần
public class QuanLyKhoTuan {
public static void main(String[] args) {
String[] sanPham = {"Cà phê", "Sữa", "Đường"};
String[] ngay = {"T2", "T3", "T4", "T5", "T6"};
int[][] tonKho = {
{50, 48, 45, 42, 40}, // Cà phê (kg)
{30, 28, 32, 30, 28}, // Sữa (lít)
{20, 19, 18, 22, 20} // Đường (kg)
};
System.out.println("📦 TỒN KHO TUẦN:\n");
for (int i = 0; i < sanPham.length; i++) {
System.out.println(sanPham[i] + ":");
for (int j = 0; j < ngay.length; j++) {
System.out.printf(" %s: %2d", ngay[j], tonKho[i][j]);
// Cảnh báo nếu < 25
if (tonKho[i][j] < 25) {
System.out.print(" ⚠️");
}
System.out.println();
}
System.out.println();
}
}
}
Bài Tập 3: Tính Trung Bình Từng Hàng/Cột
public class TinhTrungBinh {
public static void main(String[] args) {
int[][] diem = {
{8, 9, 7}, // Nhân viên 1
{7, 8, 9}, // Nhân viên 2
{9, 9, 8} // Nhân viên 3
};
String[] nhanVien = {"Minh", "Lan", "Hoa"};
String[] tieuChi = {"Phục vụ", "Pha chế", "Vệ sinh"};
System.out.println("⭐ ĐÁNH GIÁ NHÂN VIÊN:\n");
// Tính trung bình từng nhân viên
for (int i = 0; i < nhanVien.length; i++) {
int tong = 0;
for (int j = 0; j < diem[i].length; j++) {
tong += diem[i][j];
}
double trungBinh = (double) tong / diem[i].length;
System.out.printf("%s: %.1f điểm%n", nhanVien[i], trungBinh);
}
System.out.println("\n📊 TRUNG BÌNH TỪNG TIÊU CHÍ:\n");
// Tính trung bình từng tiêu chí
for (int j = 0; j < tieuChi.length; j++) {
int tong = 0;
for (int i = 0; i < diem.length; i++) {
tong += diem[i][j];
}
double trungBinh = (double) tong / diem.length;
System.out.printf("%s: %.1f điểm%n", tieuChi[j], trungBinh);
}
}
}
⚠️ Lỗi Thường Gặp
Lỗi 1: Nhầm Hàng Và Cột
// ❌ SAI: Nhầm thứ tự hàng/cột
int[][] data = {{1, 2}, {3, 4}};
int value = data[1][0]; // Hàng 1, cột 0 → 3
// Nếu nghĩ ngược: cột 1, hàng 0 → SAI!
Lỗi 2: Quên Kiểm Tra Chiều Dài
// ❌ SAI: Giả định tất cả hàng có cùng độ dài
int[][] jagged = {{1, 2}, {3, 4, 5}};
for (int i = 0; i < jagged.length; i++) {
for (int j = 0; j < jagged[0].length; j++) { // ❌ Lỗi tại hàng 2!
System.out.print(jagged[i][j]);
}
}
// ✅ ĐÚNG: Kiểm tra từng hàng
for (int i = 0; i < jagged.length; i++) {
for (int j = 0; j < jagged[i].length; j++) { // ✅ OK
System.out.print(jagged[i][j]);
}
}
Lỗi 3: Khởi Tạo Sai
// ❌ SAI: Chỉ tạo mảng hàng, chưa tạo mảng cột
int[][] data = new int[3][];
data[0][0] = 10; // ❌ NullPointerException!
// ✅ ĐÚNG: Tạo cả hàng và cột
int[][] data = new int[3][3];
data[0][0] = 10; // ✅ OK
Lỗi 4: Nhầm Length
int[][] data = {{1, 2, 3}, {4, 5, 6}};
// data.length → Số hàng (2)
// data[0].length → Số cột hàng 0 (3)
// data[1].length → Số cột hàng 1 (3)
💡 Bí Quyết Của Barista
- arr[hàng][cột]: Hàng trước, cột sau
- arr.length: Số hàng
- arr[i].length: Số cột của hàng i
- Mảng jagged: Mỗi hàng có thể khác độ dài
- Nested loop: Vòng ngoài = hàng, vòng trong = cột
- Kiểm tra bounds: Luôn check length trước khi truy cập
🎓 Bạn Đã Học Được
- ✅ Mảng 2D = Mảng của mảng (bảng)
- ✅ Khai báo:
type[][] name = {{...}, {...}}
- ✅ Truy cập:
arr[hàng][cột]
- ✅ Duyệt với nested loop (2 vòng for)
- ✅ Mảng jagged (không đều)
- ✅ Tính tổng, tìm max, trung bình
- ✅ Ứng dụng: Bảng giá, sơ đồ, ma trận
☕ Món Tiếp Theo
Đã biết mảng đa chiều! Giờ học về ArrayList:
💡 Lời Khuyên Cuối: Mảng 2D như bảng menu treo tường - dễ nhìn, dễ tìm khi sắp xếp hàng/cột rõ ràng!