L5. Mảng (Array) trong C++¤
Phần 1: Mảng Một Chiều¤
1. Giới Thiệu Về Mảng¤
Đặt vấn đề:
// Cần lưu trữ 3 số thực
float a, b, c; // OK
// Cần lưu trữ 10 số thực
float a1, a2, a3, ..., a10; // Khó quản lý
// Cần lưu trữ 100 hoặc 1000 số thực
// → Không thể khai báo 100 hoặc 1000 biến!
Giải pháp: Sử dụng MẢNG
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│1.3 │9.4 │2.7 │6.2 │4.9 │7.7 │3.5 │8.6 │0.1 │5.4 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
0 1 2 3 4 5 6 7 8 9
2. Khái Niệm Mảng¤
Định nghĩa:
Mảng là một dãy các phần tử có cùng kiểu dữ liệu, mỗi phần tử biểu diễn một giá trị.
Đặc điểm:
- Kích thước mảng được xác định ngay khi khai báo và không thay đổi
- Là kiểu dữ liệu có cấu trúc do người lập trình định nghĩa
- C++ luôn chỉ định một khối nhớ liên tục cho mảng
Ví dụ minh họa:
Mảng 1 chiều:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 5 │ T │ 8 │ B │ 2 │ R │ 7 │ K │ 1 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘
Mảng 2 chiều (Ma trận):
┌───┬───┐ ┌───┬───┬───┐ ┌───┬───┐
│ 3 │ 7 │ │ 3 │ 7 │ 8 │ │ 6 │ 7 │
├───┼───┤ ├───┼───┼───┤ ├───┼───┤
│ 6 │ 1 │ │ 6 │ 1 │ 4 │ │ 1 │ 1 │
└───┴───┘ └───┴───┴───┘ ├───┼───┤
2×2 (vuông) 2×3 (dòng<cột) │ 6 │ 3 │
└───┴───┘
3×2 (dòng>cột)
3. Các Yếu Tố Xác Định Mảng¤
Một mảng được xác định bởi 4 yếu tố:
graph TD
A[Mảng] --> B[1. Tên mảng]
A --> C[2. Kiểu dữ liệu]
A --> D[3. Số chiều]
A --> E[4. Kích thước]
Ví dụ 1:
- Tên mảng:MangKyTu
- Kiểu mảng: char
- Số chiều: 1 chiều
- Kích thước: 4 phần tử
Ví dụ 2:
- Tên mảng:MangSoNguyen
- Kiểu mảng: int
- Số chiều: 2 chiều
- Kích thước: 3 dòng × 2 cột
4. Mảng Một Chiều¤
4.1. Khai Báo Mảng 1 Chiều¤
Cú pháp:
Ví dụ:
char A[10];
// Kiểu dữ liệu: char
// Tên biến mảng: A
// Số phần tử: 10
int Mang1Chieu[30];
// Kiểu dữ liệu: int
// Tên biến mảng: Mang1Chieu
// Số phần tử: 30
Quy tắc khai báo
- Phải xác định cụ thể số phần tử ngay lúc khai báo
- KHÔNG được sử dụng biến:
- KHÔNG được sử dụng hằng const:
- NÊN sử dụng
#define:
4.2. Khởi Tạo Mảng 1 Chiều¤
Cách 1: Khởi tạo đầy đủ
Cách 2: Khởi tạo một phần
Cách 3: Khởi tạo tất cả = 0
Cách 4: Tự động xác định kích thước
4.3. Chỉ Số Mảng¤
Đặc điểm:
- Chỉ số mảng là giá trị số nguyên int
- Chỉ số bắt đầu từ 0
- Chỉ số tối đa = Số phần tử - 1
Các chỉ số hợp lệ: 0, 1, 2, 3, 4
┌────┬────┬────┬────┬────┐
│ 99 │ 17 │ 50 │ 43 │ 72 │
└────┴────┴────┴────┴────┘
0 1 2 3 4
↑ ↑
Chỉ số đầu Chỉ số cuối
Số lượng chỉ số = Số phần tử = 5
4.4. Truy Xuất Phần Tử Mảng¤
Cú pháp:
Ví dụ:
int A[4] = {29, 137, 50, 4};
// Truy xuất hợp lệ
A[0] // = 29
A[1] // = 137
A[2] // = 50
A[3] // = 4
// Truy xuất KHÔNG hợp lệ
A[-1] // SAI: chỉ số âm
A[4] // SAI: vượt quá giới hạn
A[5] // SAI: vượt quá giới hạn
4.5. Địa Chỉ Các Phần Tử Mảng¤
Cú pháp:
Ví dụ:
int A[4] = {29, 137, 50, 4};
// Địa chỉ các phần tử
&A[0] // Địa chỉ phần tử thứ 0
&A[1] // Địa chỉ phần tử thứ 1
&A[2] // Địa chỉ phần tử thứ 2
&A[3] // Địa chỉ phần tử thứ 3
┌────┬─────┬────┬───┐
Giá trị: │ 29 │ 137 │ 50 │ 4 │
└────┴─────┴────┴───┘
Địa chỉ: 0x10 0x14 0x18 0x1C
Chỉ số: 0 1 2 3
4.6. Truyền Mảng Cho Hàm¤
Khai báo tham số:
void SapXep(int A[100], int n);
// Tên hàm: SapXep
// Tham số: mảng số nguyên A và số lượng phần tử n
// Giá trị trả về: void
int TinhTong(int A[100], int n);
// Tên hàm: TinhTong
// Tham số: mảng số nguyên A và số lượng phần tử n
// Giá trị trả về: int
Đặc điểm quan trọng
- Mảng có thể thay đổi nội dung sau khi thực hiện hàm
- Có thể bỏ số lượng phần tử hoặc sử dụng con trỏ:
Ví dụ đầy đủ:
#include <stdio.h>
#include <conio.h>
void Nhap(int A[], int &N); // Nhập mảng
void Xuat(int A[], int N); // Xuất mảng
int TinhTong(int A[], int N); // Tính tổng
void main() {
int a[100], n, S;
Nhap(a, n);
Xuat(a, n);
S = TinhTong(a, n);
cout << "Tong cac phan tu trong mang: " << S;
}
5. Các Tác Vụ Trên Mảng 1 Chiều¤
5.1. Nhập Mảng¤
void nhapmang(int A[], int N) {
for (int i = 0; i < N; i++) {
cout << "Nhap phan tu thu " << i << ": ";
cin >> A[i];
}
}
5.2. Xuất Mảng¤
5.3. Tìm Kiếm Phần Tử¤
int TimKiem(int a[], int n, int x) {
for (int vt = 0; vt < n; vt++) {
if (a[vt] == x)
return vt; // Trả về vị trí tìm thấy
}
return -1; // Không tìm thấy
}
5.4. Tìm Giá Trị Lớn Nhất¤
int Max(int a[], int n) {
int Max = a[0]; // Giả sử phần tử đầu là lớn nhất
for (int i = 1; i < n; i++) {
if (Max < a[i]) // Áp dụng kỹ thuật lính canh
Max = a[i];
}
return Max;
}
5.5. Kiểm Tra Tính Chất Mảng¤
Yêu cầu: Kiểm tra mảng có toàn số nguyên tố không?
Ý tưởng 1: Đếm số lượng số nguyên tố, nếu = n thì toàn nguyên tố
// Hàm kiểm tra số nguyên tố
int LaSNT(int n) {
if (n < 2) return 0;
for (int i = 2; i < n; i++) {
if (n % i == 0)
return 0; // Không phải SNT
}
return 1; // Là SNT
}
// Ý tưởng 1
int KiemTra_YT1(int a[], int n) {
int dem = 0;
for (int i = 0; i < n; i++) {
if (LaSNT(a[i]) == 1)
dem++;
}
if (dem == n)
return 1; // Toàn SNT
return 0;
}
Ý tưởng 2: Đếm số không phải nguyên tố, nếu = 0 thì toàn nguyên tố
int KiemTra_YT2(int a[], int n) {
int dem = 0;
for (int i = 0; i < n; i++) {
if (LaSNT(a[i]) == 0)
dem++;
}
if (dem == 0)
return 1; // Toàn SNT
return 0;
}
Ý tưởng 3: Tìm phần tử không phải nguyên tố (Tối ưu nhất)
int KiemTra_YT3(int a[], int n) {
for (int i = 0; i < n; i++) {
if (LaSNT(a[i]) == 0)
return 0; // Tìm thấy số không phải SNT
}
return 1; // Không tìm thấy số nào không phải SNT
}
5.6. Đếm Số Lượng Phần Tử Chẵn¤
int DemChan(int A[], int N) {
int DC = 0;
for (int i = 0; i < n; i++) {
if (A[i] % 2 == 0)
DC++;
}
return DC;
}
Sử dụng:
int main() {
int a[100], n, DC;
nhap(a, n);
xuat(a, n);
DC = DemChan(a, n);
printf("So ptu chan la %d", DC);
}
5.7. Tính Tổng Các Phần Tử Chẵn¤
int TongChan(int A[], int N) {
int TC = 0;
for (int i = 0; i < n; i++) {
if (A[i] % 2 == 0)
TC = TC + A[i];
}
return TC;
}
Sử dụng:
int main() {
int a[100], n, TC;
nhap(a, n);
xuat(a, n);
TC = TongChan(a, n);
printf("Tong ptu chan la %d", TC);
}
6. Bài Tập Bắt Buộc - Mảng 1 Chiều¤
Bài 1: Nhập dãy tăng dần
Viết chương trình nhập vào một dãy tăng dần (không cần sắp xếp). Nếu nhập sai yêu cầu nhập lại. Sau đó xuất các số nguyên tố có trong mảng.
Gợi ý: Trong vòng lặp nhập, kiểm tra A[i] > A[i-1]
Bài 2: Kiểm tra đối xứng
Kiểm tra mảng có đối xứng hay không?
Gợi ý: So sánh A[i] với A[n-1-i]
Bài 3: Giá trị xuất hiện đúng 1 lần
Liệt kê các giá trị xuất hiện trong mảng đúng 1 lần.
Gợi ý: Với mỗi phần tử, đếm số lần xuất hiện
Bài 4: Phần tử âm lớn nhất
Tìm vị trí của phần tử có giá trị âm lớn nhất trong mảng số nguyên.
Gợi ý: Tìm max trong các số âm
Bài 5: Xóa phần tử
Viết hàm xóa phần tử có chỉ số k trong mảng số nguyên a có n phần tử.
- Nếu k < 0 hoặc k >= n: không xóa, trả về 0
- Ngược lại: xóa a[k], trả về 1
Gợi ý: Dịch các phần tử từ vị trí k+1 về trái
Tổng kết Mảng 1 Chiều
Khái niệm:
- Mảng là dãy phần tử cùng kiểu, lưu liên tục
- Chỉ số từ 0 đến n-1
Khai báo và khởi tạo:
int a[100];- Khai báoint a[] = {1,2,3};- Khởi tạo tự độngint a[5] = {0};- Khởi tạo tất cả = 0
Truy xuất:
a[i]- Truy xuất giá trị&a[i]- Lấy địa chỉ
Truyền cho hàm:
void ham(int a[], int n)- Mảng có thể thay đổi- Luôn truyền kèm kích thước
Các thao tác cơ bản:
- Nhập/xuất, tìm kiếm, tìm min/max
- Đếm, tính tổng, kiểm tra tính chất
Chương tiếp theo: Mảng hai chiều và chuỗi ký tự