📊 Mảng 1 chiều trong C++
📖 Giới thiệu
Mảng (array) là cấu trúc dữ liệu cho phép lưu trữ nhiều giá trị cùng kiểu trong một biến duy nhất. Thay vì phải khai báo nhiều biến riêng lẻ, chúng ta có thể sử dụng mảng để quản lý một tập hợp dữ liệu có tổ chức.
Tưởng tượng mảng như một dãy hộp được đánh số từ 0, mỗi hộp chứa một giá trị. Ví dụ: điểm số của 30 học sinh trong lớp, nhiệt độ của 365 ngày trong năm, hay danh sách 100 số nguyên cần sắp xếp.
Mảng 1 chiều là nền tảng để hiểu các cấu trúc dữ liệu phức tạp hơn như mảng 2 chiều, vector, và các container khác trong C++.
🔧 Cú pháp
Ví dụ đơn giản để bắt đầu
Trước khi tìm hiểu chi tiết, hãy xem ví dụ đơn giản nhất về mảng:
#include <iostream>
using namespace std;
int main() {
// Tạo mảng 3 số
int so[3] = {5, 10, 15};
// In ra các số
cout << "Số thứ 1: " << so[0] << endl;
cout << "Số thứ 2: " << so[1] << endl;
cout << "Số thứ 3: " << so[2] << endl;
// Thay đổi một số
so[1] = 20;
cout << "Số thứ 2 mới: " << so[1] << endl;
return 0;
}Kết quả:
Số thứ 1: 5
Số thứ 2: 10
Số thứ 3: 15
Số thứ 2 mới: 20Cú pháp chi tiết
Khai báo và khởi tạo mảng
// Khai báo mảng với kích thước cố định
int arr[10]; // Mảng 10 số nguyên (chưa khởi tạo)
double scores[5]; // Mảng 5 số thực
// Khai báo và khởi tạo với danh sách
int numbers[5] = {1, 2, 3, 4, 5}; // Khởi tạo đầy đủ
int partial[5] = {1, 2}; // Các phần tử còn lại = 0
int automatic[] = {10, 20, 30, 40}; // Tự động xác định kích thước = 4
// Khởi tạo tất cả phần tử = 0
int zeros[100] = {0}; // Phần tử đầu = 0, còn lại tự động = 0
int allZeros[50] = {}; // Tất cả = 0Truy cập phần tử mảng
int arr[5] = {10, 20, 30, 40, 50};
// Đọc giá trị (chỉ số bắt đầu từ 0)
int first = arr[0]; // first = 10
int last = arr[4]; // last = 50
// Gán giá trị
arr[0] = 100; // arr = {100, 20, 30, 40, 50}
arr[2] = arr[1] + arr[3]; // arr[2] = 20 + 40 = 60Duyệt mảng với vòng lặp
int arr[5] = {1, 2, 3, 4, 5};
int size = 5;
// Duyệt từ đầu đến cuối
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
// Duyệt ngược
for (int i = size - 1; i >= 0; i--) {
cout << arr[i] << " ";
}
// Range-based for loop (C++11)
for (int element : arr) {
cout << element << " ";
}Tìm kích thước mảng
int arr[] = {1, 2, 3, 4, 5};
// Cách tính kích thước
int size = sizeof(arr) / sizeof(arr[0]);
// sizeof(arr) = tổng bytes của mảng
// sizeof(arr[0]) = bytes của 1 phần tử🔬 Phân tích & Giải thích chi tiết
Bộ nhớ của mảng
Mảng lưu trữ các phần tử liên tiếp trong bộ nhớ:
arr[5] = {10, 20, 30, 40, 50}
Bộ nhớ:
Address: 1000 1004 1008 1012 1016
Value: 10 20 30 40 50
Index: 0 1 2 3 4Index và bounds checking
int arr[5] = {1, 2, 3, 4, 5};
// Hợp lệ
arr[0] = 10; // Phần tử đầu tiên
arr[4] = 50; // Phần tử cuối cùng
// NGUY HIỂM - Array bounds overflow
arr[-1] = 0; // Truy cập trước mảng
arr[5] = 60; // Truy cập sau mảng
arr[100] = 0; // Rất nguy hiểm!Truyền mảng vào hàm
// Mảng được truyền bằng tham chiếu (pointer)
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
}
// Hoặc
void printArray(int* arr, int size) {
// arr là pointer đến phần tử đầu tiên
}
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
printArray(numbers, 5); // Truyền tên mảng
return 0;
}Hạn chế của mảng C-style
- Kích thước cố định: Không thể thay đổi sau khi khai báo
- Không bounds checking: Có thể truy cập ngoài phạm vi
- Mất thông tin kích thước: Khi truyền vào hàm
- Không thể copy trực tiếp:
arr1 = arr2không hoạt động
Mảng vs Vector
| Đặc điểm | Array | Vector |
|---|---|---|
| Kích thước | Cố định | Động |
| Memory | Stack | Heap |
| Safety | Không | Có bounds checking |
| Functions | Ít | Nhiều (push_back, size, etc.) |
| Performance | Nhanh hơn | Chậm hơn một chút |
💻 Ví dụ minh họa
Chương trình đơn giản với mảng
#include <iostream>
using namespace std;
int main() {
// Khai báo mảng 5 số nguyên
int numbers[5] = {10, 20, 30, 40, 50};
cout << "=== DEMO MẢNG ĐỐN GIẢN ===" << endl;
// In tất cả phần tử
cout << "Các số trong mảng: ";
for (int i = 0; i < 5; i++) {
cout << numbers[i] << " ";
}
cout << endl;
// Tính tổng
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += numbers[i];
}
cout << "Tổng các số: " << sum << endl;
// Tìm số lớn nhất
int max = numbers[0];
for (int i = 1; i < 5; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
}
cout << "Số lớn nhất: " << max << endl;
// Thay đổi một phần tử
cout << "\nThay đổi phần tử thứ 2 từ " << numbers[1] << " thành 99" << endl;
numbers[1] = 99;
// In lại mảng
cout << "Mảng sau khi thay đổi: ";
for (int i = 0; i < 5; i++) {
cout << numbers[i] << " ";
}
cout << endl;
return 0;
}Kết quả chạy:
=== DEMO MẢNG ĐỐN GIẢN ===
Các số trong mảng: 10 20 30 40 50
Tổng các số: 150
Số lớn nhất: 50
Thay đổi phần tử thứ 2 từ 20 thành 99
Mảng sau khi thay đổi: 10 99 30 40 50Chương trình quản lý điểm lớp học
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
const int MAX_STUDENTS = 50;
double scores[MAX_STUDENTS];
int studentCount;
cout << "=== QUẢN LÝ ĐIỂM LỚP HỌC ===" << endl;
cout << "Nhập số lượng học sinh (tối đa " << MAX_STUDENTS << "): ";
cin >> studentCount;
// Validation
if (studentCount <= 0 || studentCount > MAX_STUDENTS) {
cout << "Số lượng không hợp lệ!" << endl;
return 1;
}
// Nhập điểm
cout << "\nNhập điểm cho " << studentCount << " học sinh:" << endl;
for (int i = 0; i < studentCount; i++) {
cout << "Học sinh " << (i + 1) << ": ";
cin >> scores[i];
// Validation điểm
while (scores[i] < 0 || scores[i] > 10) {
cout << "Điểm phải từ 0-10. Nhập lại: ";
cin >> scores[i];
}
}
// Tính toán thống kê
double sum = 0, highest = scores[0], lowest = scores[0];
int passCount = 0, excellentCount = 0;
for (int i = 0; i < studentCount; i++) {
sum += scores[i];
if (scores[i] > highest) highest = scores[i];
if (scores[i] < lowest) lowest = scores[i];
if (scores[i] >= 5.0) passCount++;
if (scores[i] >= 8.0) excellentCount++;
}
double average = sum / studentCount;
// Hiển thị kết quả
cout << "\n" << string(40, '=') << endl;
cout << " THỐNG KÊ ĐIỂM LỚP" << endl;
cout << string(40, '=') << endl;
cout << fixed << setprecision(2);
cout << "Số học sinh: " << studentCount << endl;
cout << "Điểm trung bình: " << average << endl;
cout << "Điểm cao nhất: " << highest << endl;
cout << "Điểm thấp nhất: " << lowest << endl;
cout << "Số HS đậu (>=5): " << passCount
<< " (" << (passCount * 100.0 / studentCount) << "%)" << endl;
cout << "Số HS giỏi (>=8): " << excellentCount
<< " (" << (excellentCount * 100.0 / studentCount) << "%)" << endl;
// Hiển thị phân loại
cout << "\nDanh sách phân loại:" << endl;
for (int i = 0; i < studentCount; i++) {
cout << "HS " << setw(2) << (i + 1) << ": "
<< setw(5) << scores[i] << " - ";
if (scores[i] >= 9.0) cout << "Xuất sắc";
else if (scores[i] >= 8.0) cout << "Giỏi";
else if (scores[i] >= 6.5) cout << "Khá";
else if (scores[i] >= 5.0) cout << "Trung bình";
else cout << "Yếu";
cout << endl;
}
return 0;
}Chương trình sắp xếp mảng
#include <iostream>
using namespace std;
// Hàm in mảng
void printArray(int arr[], int size, string title) {
cout << title << ": ";
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
// Bubble Sort - sắp xếp nổi bọt
void bubbleSort(int arr[], int size) {
for (int i = 0; i < size - 1; i++) {
bool swapped = false;
for (int j = 0; j < size - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// Hoán đổi
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
// Nếu không có hoán đổi nào, mảng đã sắp xếp
if (!swapped) break;
}
}
// Selection Sort - sắp xếp chọn
void selectionSort(int arr[], int size) {
for (int i = 0; i < size - 1; i++) {
int minIndex = i;
// Tìm phần tử nhỏ nhất trong phần chưa sắp xếp
for (int j = i + 1; j < size; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// Hoán đổi phần tử nhỏ nhất về đầu
if (minIndex != i) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
int main() {
const int SIZE = 10;
int original[SIZE] = {64, 34, 25, 12, 22, 11, 90, 88, 76, 50};
int arr1[SIZE], arr2[SIZE];
// Copy mảng gốc
for (int i = 0; i < SIZE; i++) {
arr1[i] = arr2[i] = original[i];
}
cout << "=== DEMO THUẬT TOÁN SẮP XẾP ===" << endl;
printArray(original, SIZE, "Mảng gốc");
// Bubble Sort
bubbleSort(arr1, SIZE);
printArray(arr1, SIZE, "Bubble Sort");
// Selection Sort
selectionSort(arr2, SIZE);
printArray(arr2, SIZE, "Selection Sort");
return 0;
}Chương trình tìm kiếm trong mảng
#include <iostream>
using namespace std;
// Tìm kiếm tuyến tính
int linearSearch(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // Trả về chỉ số tìm thấy
}
}
return -1; // Không tìm thấy
}
// Tìm kiếm nhị phân (mảng đã sắp xếp)
int binarySearch(int arr[], int size, int target) {
int left = 0, right = size - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
// Tìm tất cả vị trí xuất hiện
void findAllOccurrences(int arr[], int size, int target) {
cout << "Các vị trí tìm thấy " << target << ": ";
bool found = false;
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
cout << i << " ";
found = true;
}
}
if (!found) {
cout << "Không tìm thấy";
}
cout << endl;
}
int main() {
int arr[] = {5, 2, 8, 12, 3, 8, 15, 8, 7};
int size = sizeof(arr) / sizeof(arr[0]);
int sortedArr[] = {2, 3, 5, 7, 8, 12, 15, 18, 22};
int sortedSize = sizeof(sortedArr) / sizeof(sortedArr[0]);
cout << "=== DEMO TÌM KIẾM TRONG MẢNG ===" << endl;
// Hiển thị mảng
cout << "Mảng gốc: ";
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
// Linear Search
int target = 8;
int result = linearSearch(arr, size, target);
if (result != -1) {
cout << "Tìm kiếm tuyến tính: " << target << " tại vị trí " << result << endl;
} else {
cout << "Không tìm thấy " << target << endl;
}
// Tìm tất cả
findAllOccurrences(arr, size, target);
// Binary Search
cout << "\nMảng đã sắp xếp: ";
for (int i = 0; i < sortedSize; i++) {
cout << sortedArr[i] << " ";
}
cout << endl;
target = 12;
result = binarySearch(sortedArr, sortedSize, target);
if (result != -1) {
cout << "Tìm kiếm nhị phân: " << target << " tại vị trí " << result << endl;
} else {
cout << "Không tìm thấy " << target << endl;
}
return 0;
}🏋️ Thực hành
Bài tập 1: Thống kê mảng
Viết chương trình thực hiện:
- Nhập mảng n số nguyên
- Tìm max, min, tổng, trung bình
- Đếm số chẵn, lẻ, số dương, âm, số 0
Bài tập 2: Xoay mảng
Viết hàm xoay mảng:
- Xoay trái k vị trí: [1,2,3,4,5] → [3,4,5,1,2] (k=2)
- Xoay phải k vị trí: [1,2,3,4,5] → [4,5,1,2,3] (k=2)
Bài tập 3: Loại bỏ phần tử
Viết chương trình:
- Loại bỏ phần tử trùng lặp
- Loại bỏ phần tử tại vị trí k
- Chèn phần tử x tại vị trí k
Bài tập 4: Mảng con
Tìm mảng con có tổng lớn nhất (Kadane's algorithm):
- Input: [-2,1,-3,4,-1,2,1,-5,4]
- Output: [4,-1,2,1] với tổng = 6
Lời giải chi tiết
Bài tập 1:
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Nhập số phần tử: ";
cin >> n;
int arr[1000]; // Giả sử tối đa 1000 phần tử
cout << "Nhập " << n << " số nguyên:" << endl;
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
// Thống kê
int sum = 0, max = arr[0], min = arr[0];
int evenCount = 0, oddCount = 0;
int positiveCount = 0, negativeCount = 0, zeroCount = 0;
for (int i = 0; i < n; i++) {
sum += arr[i];
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
if (arr[i] % 2 == 0) evenCount++; else oddCount++;
if (arr[i] > 0) positiveCount++;
else if (arr[i] < 0) negativeCount++;
else zeroCount++;
}
cout << "\nThống kê:" << endl;
cout << "Max: " << max << ", Min: " << min << endl;
cout << "Tổng: " << sum << ", TB: " << (double)sum/n << endl;
cout << "Chẵn: " << evenCount << ", Lẻ: " << oddCount << endl;
cout << "Dương: " << positiveCount << ", Âm: " << negativeCount
<< ", Zero: " << zeroCount << endl;
return 0;
}Bài tập 2:
#include <iostream>
using namespace std;
void rotateLeft(int arr[], int n, int k) {
k = k % n; // Xử lý k > n
int temp[k];
// Lưu k phần tử đầu
for (int i = 0; i < k; i++) {
temp[i] = arr[i];
}
// Dịch phần còn lại sang trái
for (int i = 0; i < n - k; i++) {
arr[i] = arr[i + k];
}
// Đặt k phần tử đầu vào cuối
for (int i = 0; i < k; i++) {
arr[n - k + i] = temp[i];
}
}
void printArray(int arr[], int n) {
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int n = 5, k = 2;
cout << "Mảng gốc: ";
printArray(arr, n);
rotateLeft(arr, n, k);
cout << "Sau khi xoay trái " << k << " vị trí: ";
printArray(arr, n);
return 0;
}📋 Tóm tắt
🎯 Những gì đã học
- Khai báo mảng:
int arr[10], khởi tạo với{...} - Truy cập phần tử:
arr[index], chỉ số bắt đầu từ 0 - Duyệt mảng: for loop, range-based for
- Tính kích thước:
sizeof(arr)/sizeof(arr[0]) - Thuật toán cơ bản: tìm kiếm, sắp xếp, thống kê
🔧 Best Practices
- Luôn check bounds khi truy cập mảng
- Truyền kích thước khi pass mảng vào hàm
- Sử dụng const cho kích thước mảng
- Khởi tạo mảng khi khai báo
- Cân nhắc sử dụng vector thay vì mảng C-style
🚀 Chuẩn bị cho bước tiếp theo
Bài học tiếp theo sẽ tìm hiểu về mảng 2 chiều. Đảm bảo bạn đã:
- [x] Thành thạo khai báo và truy cập mảng 1D
- [x] Viết được các thuật toán cơ bản trên mảng
- [x] Hiểu về index và bounds checking
- [x] Biết cách truyền mảng vào hàm
💡 Lời khuyên
"Mảng như một cuốn sách - mỗi trang (index) chứa một thông tin. Hãy đọc đúng trang để tránh 'lạc' thông tin!"
Chuyển sang: Mảng 2 chiều để học về ma trận và các ứng dụng 2D!