Bài 17: Dữ liệu mảng một chiều và hai chiều – Lý thuyết

I. Lý thuyết trọng tâm

1. Cấu trúc dữ liệu mảng một chiều

1.1. Khái niệm

Mảng một chiều (hay còn gọi là cấu trúc dữ liệu tuyến tính) là một dãy gồm nhiều phần tử có cùng kiểu dữ liệu, xếp nối tiếp nhau. Mỗi phần tử được xác định thông qua chỉ số – nhờ đó ta có thể truy cập hoặc thay đổi giá trị của bất kỳ phần tử nào một cách nhanh chóng.

Trong Python, kiểu dữ liệu danh sách (list) được dùng để biểu diễn mảng một chiều, với điều kiện các phần tử trong list cùng kiểu.

1.2. Thiết lập mảng một chiều trong Python

Để tạo một mảng, ta gán cho biến một danh sách các giá trị đặt trong cặp ngoặc vuông [], các phần tử cách nhau bởi dấu phẩy:

A = [1, 3, 5, 7, 9, 11]          # mảng số nguyên
B = ["Hà", "Bình", "Ngọc", "Anh"] # mảng xâu kí tự
C = [9.5, 8.0, 10, 7.2]           # mảng số thực

1.3. Truy cập phần tử và duyệt mảng

Truy cập theo chỉ số: Python đánh chỉ số bắt đầu từ 0. Phần tử đầu tiên là A[0], phần tử thứ hai là A[1],…

Kiểm tra phần tử có thuộc mảng hay không: Dùng toán tử in.

>>> 7 in A
True

Duyệt toàn bộ phần tử: Sử dụng vòng lặp for ... in:

>>> for hs in B:
        print(hs, end = " ")
Hà Bình Ngọc Anh

1.4. Một số thao tác cơ bản với list

Đây là các lệnh đã học từ Tin học 10, thường dùng khi làm việc với mảng:

Lệnh Chức năng
append(x) Thêm phần tử x vào cuối danh sách
insert(i, x) Chèn phần tử x vào vị trí chỉ số i
remove(x) Xoá phần tử có giá trị x (phần tử đầu tiên tìm thấy)
clear() Xoá toàn bộ phần tử trong danh sách

Lưu ý quan trọng: Mặc dù mảng được biểu diễn bằng list, hai khái niệm này không hoàn toàn đồng nhất. Mảng trong khoa học máy tính có các ràng buộc chặt chẽ hơn (cùng kiểu, kích thước cố định,…), trong khi list của Python linh hoạt hơn nhiều.

2. Cấu trúc dữ liệu mảng hai chiều

2.1. Mô hình danh sách trong danh sách

Python cho phép mỗi phần tử của một danh sách lại là một danh sách khác. Đây chính là nền tảng để biểu diễn dữ liệu hai chiều.

Ví dụ: Lưu trữ tên và điểm của học sinh, mỗi phần tử gồm hai thành phần [tên, điểm]:

DS_diem = [["Quang", 7.5], ["Hà", 8.0], ["Bình", 9.5]]

Truy cập một phần tử của danh sách gốc → nhận được cả danh sách con:

>>> DS_diem[1]
['Hà', 8.0]

Truy cập giá trị cụ thể bên trong → dùng hai chỉ số liên tiếp:

>>> DS_diem[0][1]    # điểm của "Quang"
7.5

Duyệt danh sách trong danh sách với nhiều biến trong for:

>>> for hs, diem in DS_diem:
        print(hs, diem)
Quang 7.5
Hà 8.0
Bình 9.5

2.2. Mảng hai chiều – Ma trận

Trong tin học, cấu trúc dữ liệu hai chiều thường được hình dung như một bảng (hay ma trận) gồm các hàng và cột. Bảng có thể có kích thước vuông n × n hoặc kích thước tuỳ ý m × n (m hàng, n cột). Phần tử nằm ở hàng i, cột j được kí hiệu là ij;.

Trong Python, ma trận m × n được biểu diễn bằng một danh sách gồm m phần tử, mỗi phần tử là một danh sách gồm n giá trị.

Ví dụ: Ma trận vuông bậc 3:

A = [[12, 10, 91],
     [11, 45, 20],
     [15, 34, 55]]

Tương ứng với bảng:

Cột 0 Cột 1 Cột 2
Hàng 0 12 10 91
Hàng 1 11 45 20
Hàng 2 15 34 55

Truy cập phần tử: Vì chỉ số bắt đầu từ 0, để lấy phần tử hàng 3 cột 2 (theo cách đánh số toán học), ta dùng A[2][1]:

>>> A[2][1]
34

2.3. Duyệt mảng hai chiều bằng hai vòng for lồng nhau

Để đi qua tất cả phần tử của ma trận, ta dùng vòng for ngoài duyệt theo hàng và vòng for trong duyệt theo cột:

for i in range(3):
    for j in range(3):
        print(A[i][j], end = " ")
    print()

Kết quả in ra đúng dạng bảng:

12 10 91
11 45 20
15 34 55

II. Phương pháp giải các dạng bài tập

Dạng 1: Tính toán trên mảng một chiều

Phương pháp: Dùng vòng lặp for để duyệt mảng, kết hợp các hàm có sẵn như sum(), len() để tính tổng, đếm số phần tử. Khi cần đếm phần tử thoả điều kiện, thêm lệnh if bên trong vòng lặp.

Bài 1 (Luyện tập SGK). Giả sử số đo chiều cao các bạn trong lớp được cho trong dãy số A. Hãy viết đoạn chương trình tính: a) Chiều cao trung bình của cả lớp. b) Số bạn có chiều cao lớn hơn chiều cao trung bình.

Lời giải:

A = [165, 170, 158, 172, 168, 160, 175, 163]

# a) Tính chiều cao trung bình
tb = sum(A) / len(A)
print("Chiều cao trung bình:", tb)

# b) Đếm số bạn có chiều cao lớn hơn trung bình
dem = 0
for x in A:
    if x > tb:
        dem += 1
print("Số bạn cao hơn trung bình:", dem)

Giải thích: sum(A) trả về tổng tất cả phần tử, len(A) trả về số phần tử. Chia hai giá trị này ta được trung bình cộng. Sau đó duyệt từng phần tử, so sánh với giá trị trung bình và tăng biến đếm khi thoả điều kiện.

Dạng 2: Nhập và in ma trận

Phương pháp: Dùng vòng lặp for để nhập từng hàng. Mỗi hàng nhập dưới dạng chuỗi, sau đó tách bằng split() và chuyển sang số. In ma trận bằng hai vòng for lồng nhau.

Bài 2 (Luyện tập SGK). Viết chương trình nhập từ bàn phím số tự nhiên m, sau đó lần lượt nhập m dòng, mỗi dòng bao gồm n số cách nhau bởi dấu cách, đưa dữ liệu đã nhập vào ma trận A, sau đó in ma trận A ra màn hình.

Lời giải:

m = int(input("Nhập số hàng m: "))
A = []
for i in range(m):
    dong = input(f"Nhập hàng {i + 1} (các số cách nhau bởi dấu cách): ")
    hang = [int(x) for x in dong.split()]
    A.append(hang)

# In ma trận
n = len(A[0])
for i in range(m):
    for j in range(n):
        print(A[i][j], end = " ")
    print()

Giải thích: Với mỗi hàng, ta nhập một chuỗi, dùng split() để tách thành danh sách các xâu, rồi chuyển từng xâu thành số nguyên bằng list comprehension. Cuối cùng thêm hàng đó vào ma trận A bằng append().

Dạng 3: Tạo ma trận đặc biệt

Phương pháp: Phân tích quy luật giá trị phần tử theo vị trí hàng – cột, từ đó xây dựng ma trận bằng vòng lặp lồng nhau.

Bài 3 (Vận dụng SGK). Viết hàm UnitMatrix(n) với n là số tự nhiên cho trước, hàm trả lại giá trị là ma trận đơn vị bậc n (đường chéo chính bằng 1, các vị trí còn lại bằng 0).

Lời giải:

def UnitMatrix(n):
    E = []
    for i in range(n):
        hang = []
        for j in range(n):
            if i == j:
                hang.append(1)
            else:
                hang.append(0)
        E.append(hang)
    return E

# Thử nghiệm
n = int(input("Nhập n: "))
E = UnitMatrix(n)
for i in range(n):
    for j in range(n):
        print(E[i][j], end = " ")
    print()

Giải thích: Ma trận đơn vị có đặc điểm: phần tử tại hàng i cột j bằng 1 nếu i == j (nằm trên đường chéo chính), bằng 0 nếu i != j. Ta dùng hai vòng lặp lồng nhau để tạo từng phần tử theo quy luật này.

Dạng 4: Đếm và thống kê trên mảng

Phương pháp: Duyệt mảng để tìm các giá trị phân biệt, sau đó đếm số lần xuất hiện của mỗi giá trị bằng phương thức count() hoặc dùng biến đếm thủ công.

Bài 4 (Vận dụng SGK). Viết chương trình cho phép nhập một dãy số tự nhiên từ bàn phím, rồi đếm xem mỗi giá trị xuất hiện bao nhiêu lần.

Lời giải:

chuoi = input("Nhập dãy số (cách nhau bởi dấu cách): ")
A = [int(x) for x in chuoi.split()]

da_dem = []
for x in A:
    if x not in da_dem:
        print(f"Số {x} lặp lại {A.count(x)} lần")
        da_dem.append(x)

Giải thích: Danh sách da_dem lưu các giá trị đã được thống kê để tránh in trùng. Với mỗi phần tử chưa đếm, ta dùng A.count(x) để đếm số lần xuất hiện trong toàn bộ dãy.

Dạng 5: Xử lí bảng dữ liệu hai chiều thực tế

Phương pháp: Biểu diễn bảng dữ liệu dưới dạng ma trận (danh sách trong danh sách), sau đó dùng vòng lặp để tính toán theo hàng, theo cột, hoặc trên toàn bảng tuỳ yêu cầu.

Bài 5 (Vận dụng SGK). Tiền điện gia đình ghi theo từng tháng, mỗi năm là một danh sách 12 số. Nhiều năm ghép lại thành bảng kích thước n × 12. Hãy: a) Tính tiền điện trung bình của mỗi năm. b) Tính tiền điện trung bình của tất cả các năm.

Lời giải:

# Ví dụ dữ liệu 3 năm
tien_dien = [
    [350, 400, 380, 420, 500, 550, 600, 580, 520, 450, 380, 360],
    [370, 410, 390, 430, 510, 560, 620, 590, 530, 460, 390, 370],
    [380, 420, 400, 450, 530, 580, 640, 610, 550, 470, 400, 380]
]

n = len(tien_dien)

# a) Trung bình mỗi năm
tb_nam = []
for i in range(n):
    tb = sum(tien_dien[i]) / 12
    tb_nam.append(tb)
    print(f"Năm {i + 1}: trung bình = {tb:.0f}")

# b) Trung bình tất cả các năm
tong_tat_ca = sum(tb_nam) / n
print(f"Trung bình tất cả các năm: {tong_tat_ca:.0f}")

Giải thích: Mỗi hàng tien_dien[i] chứa 12 giá trị tương ứng 12 tháng. Dùng sum() chia cho 12 để tính trung bình từng năm. Trung bình chung bằng trung bình cộng của các giá trị trung bình năm.

III. Sơ đồ tư duy

                          ┌─ Khái niệm: dãy phần tử cùng kiểu, truy cập theo chỉ số
        ┌─ Mảng 1 chiều ─┼─ Python: biểu diễn bằng list
        │                 ├─ Chỉ số từ 0: A[0], A[1],...
        │                 ├─ Toán tử in: kiểm tra phần tử có trong mảng
        │                 ├─ for ... in: duyệt từng phần tử
        │                 └─ append, remove, insert, clear
        │
        │                 ┌─ Danh sách trong danh sách
        │                 │   VD: [["Quang", 7.5], ["Hà", 8.0]]
 DỮ     │                 │   Truy cập: DS[0][1] → 7.5
 LIỆU   ├─ Mảng 2 chiều ─┤
 MẢNG   │                 ├─ Ma trận m × n
        │                 │   VD: A = [[12,10,91],[11,45,20],[15,34,55]]
        │                 │   Truy cập: A[hàng][cột]
        │                 │
        │                 └─ Duyệt: hai vòng for lồng nhau
        │                     for i in range(m):
        │                         for j in range(n):
        │
        └─ Lưu ý ────────── list ≠ mảng (list linh hoạt hơn mảng trong KHMT)
Thầy Phạm Thành Danh

Thầy Phạm Thành Danh

(Người kiểm duyệt, ra đề)

Chức vụ: Trưởng ban biên soạn môn Tin Học THPT

Trình độ: Cử nhân Sư phạm Tin học, Chứng chỉ hạng II, Chứng chỉ Tin học, Ngoại ngữ B1

Kinh nghiệm: 8+ năm kinh nghiệm tại Trường THPT Thuận Hóa