Bài 12.5: Bài tập thực hành ứng dụng mảng 1 chiều trong C++

Chào mừng bạn đến với bài thực hành quan trọng về mảng một chiều trong chuỗi bài học C++ của chúng ta! Sau khi đã nắm vững các khái niệm cơ bản về cách khai báo, truy cập và khởi tạo mảng, đây là lúc chúng ta áp dụng kiến thức đó vào các bài tập thực tế. Thực hành chính là cầu nối vững chắc giữa lý thuyết và khả năng giải quyết vấn đề thực tế trong lập trình.

Mảng một chiều là một trong những cấu trúc dữ liệu cơ bản nhất nhưng lại cực kỳ mạnh mẽ và được sử dụng rộng rãi. Việc thành thạo thao tác với mảng là nền tảng quan trọng cho việc học các cấu trúc dữ liệu phức tạp hơn sau này.

Bài tập 1: Nhập và Xuất mảng cơ bản

Yêu cầu bài toán: Viết chương trình C++ cho phép người dùng nhập vào số lượng phần tử n, sau đó nhập n số nguyên và lưu trữ chúng vào một mảng. Cuối cùng, in ra toàn bộ các phần tử của mảng vừa nhập.

Ý tưởng giải quyết: Chúng ta sẽ cần:

  • Hỏi người dùng kích thước mảng.
  • Khai báo một mảng (hoặc vector) với kích thước đó.
  • Sử dụng vòng lặp for để đọc từng phần tử từ người dùng và gán vào mảng.
  • Sử dụng một vòng lặp for khác để duyệt qua mảng và in từng phần tử ra màn hình.

Mã nguồn minh họa:

#include <iostream>
#include <vector>

int main() {
    using namespace std;
    int n;
    cout << "Nhap so luong phan tu cua mang: ";
    cin >> n;

    vector<int> a(n);

    cout << "Nhap " << n << " so nguyen vao mang:\n";
    for (int i = 0; i < n; ++i) {
        cout << "Phan tu thu " << i << ": ";
        cin >> a[i];
    }

    cout << "\nCac phan tu trong mang la:\n";
    for (int i = 0; i < n; ++i) {
        cout << a[i] << " ";
    }
    cout << endl;

    return 0;
}

Output ví dụ:

Nhap so luong phan tu cua mang: 3
Nhap 3 so nguyen vao mang:
Phan tu thu 0: 10
Phan tu thu 1: 20
Phan tu thu 2: 30

Cac phan tu trong mang la:
10 20 30

Giải thích code:

  • Chúng ta bao gồm thư viện <iostream> cho nhập/xuất và <vector> để sử dụng vector. vector giống như mảng nhưng linh hoạt hơn về kích thước.
  • cout << "Nhap so luong phan tu..."cin >> n; để lấy kích thước mảng từ người dùng.
  • vector<int> a(n); khai báo một vector tên a chứa các số nguyên và có kích thước là n.
  • Vòng lặp for (int i = 0; i < n; ++i) đầu tiên chạy từ i = 0 đến n-1. Trong mỗi lần lặp, cin >> a[i]; đọc một số nguyên từ người dùng và lưu vào phần tử thứ i của vector.
  • Vòng lặp for thứ hai cũng chạy từ i = 0 đến n-1. Trong mỗi lần lặp, cout << a[i] << " "; in ra phần tử thứ i của vector, theo sau là một khoảng trắng để các số cách nhau.
  • endl; kết thúc dòng output cuối cùng.

Bài tập 2: Tính tổng và Trung bình cộng các phần tử

Yêu cầu bài toán: Cho một mảng các số nguyên. Tính tổng và trung bình cộng của tất cả các phần tử trong mảng đó.

Ý tưởng giải quyết:

  • Duyệt qua tất cả các phần tử trong mảng.
  • Sử dụng một biến để lưu trữ tổng. Cộng giá trị của từng phần tử vào biến tổng này.
  • Sau khi duyệt xong, chia tổng cho số lượng phần tử để tính trung bình cộng. Cần cẩn thận với phép chia số nguyên.

Mã nguồn minh họa:

#include <iostream>
#include <vector>

int main() {
    using namespace std;
    vector<int> a = {10, 25, 5, 30, 15};

    long long tong = 0;
    for (size_t i = 0; i < a.size(); ++i) {
        tong += a[i];
    }

    double tb = 0.0;
    if (!a.empty()) {
        tb = static_cast<double>(tong) / a.size();
    }

    cout << "Mang: ";
    for (size_t i = 0; i < a.size(); ++i) {
         cout << a[i] << (i == a.size() - 1 ? "" : " ");
    }
    cout << endl;

    cout << "Tong cac phan tu: " << tong << endl;
    cout << "Trung binh cong cac phan tu: " << tb << endl;

    return 0;
}

Output ví dụ:

Mang: 10 25 5 30 15
Tong cac phan tu: 85
Trung binh cong cac phan tu: 17

Giải thích code:

  • Chúng ta khai báo một vector<int> a với các giá trị mẫu.
  • Biến tong được khởi tạo bằng 0. Chúng ta sử dụng kiểu long long cho tong để đảm bảo nó có thể chứa tổng lớn mà không bị tràn số (integer overflow).
  • Vòng lặp for (size_t i = 0; i < a.size(); ++i) duyệt qua từng phần tử. a.size() trả về số lượng phần tử trong vector (kích thước mảng). Kiểu size_t thường dùng cho kích thước và chỉ số.
  • tong += a[i]; cộng giá trị của phần tử hiện tại (a[i]) vào tong.
  • Trước khi tính trung bình, chúng ta kiểm tra !a.empty() để đảm bảo mảng không rỗng, tránh lỗi chia cho 0.
  • tb = static_cast<double>(tong) / a.size(); tính trung bình. static_cast<double>(tong) ép kiểu tổng sang số thực trước khi chia, đảm bảo kết quả là số thực (trung bình cộng thường có phần thập phân).
  • Cuối cùng, in ra mảng, tổng và trung bình cộng. Vòng lặp in mảng sử dụng toán tử ba ngôi (i == a.size() - 1 ? "" : " ") để không in khoảng trắng sau phần tử cuối cùng.

Bài tập 3: Tìm phần tử lớn nhất và nhỏ nhất

Yêu cầu bài toán: Tìm giá trị phần tử lớn nhất và giá trị phần tử nhỏ nhất trong một mảng các số nguyên.

Ý tưởng giải quyết:

  • Giả định rằng phần tử đầu tiên của mảng vừa là lớn nhất, vừa là nhỏ nhất ban đầu.
  • Duyệt qua các phần tử còn lại của mảng (bắt đầu từ phần tử thứ hai).
  • Trong mỗi lần lặp, so sánh phần tử hiện tại với giá trị lớn nhất và nhỏ nhất đã ghi nhận. Cập nhật nếu tìm thấy giá trị mới lớn hơn hoặc nhỏ hơn.

Mã nguồn minh họa:

#include <iostream>
#include <vector>

int main() {
    using namespace std;
    vector<int> a = {10, 4, 8, 20, 1, 15};

    if (a.empty()) {
        cout << "Mang rong, khong the tim max/min." << endl;
        return 1;
    }

    int lonNhat = a[0];
    int nhoNhat = a[0];

    for (size_t i = 1; i < a.size(); ++i) {
        if (a[i] > lonNhat) {
            lonNhat = a[i];
        }
        if (a[i] < nhoNhat) {
            nhoNhat = a[i];
        }
    }

    cout << "Mang: ";
    for (int gt : a) {
         cout << gt << " ";
    }
    cout << endl;

    cout << "Phan tu lon nhat: " << lonNhat << endl;
    cout << "Phan tu nho nhat: " << nhoNhat << endl;

    return 0;
}

Output ví dụ:

Mang: 10 4 8 20 1 15
Phan tu lon nhat: 20
Phan tu nho nhat: 1

Giải thích code:

  • Chúng ta kiểm tra nếu a.empty() để tránh truy cập phần tử khi mảng rỗng.
  • Biến lonNhatnhoNhat được khởi tạo bằng giá trị của phần tử đầu tiên a[0]. Đây là điểm bắt đầu so sánh.
  • Vòng lặp for (size_t i = 1; i < a.size(); ++i) bắt đầu từ chỉ số 1 (phần tử thứ hai) vì phần tử 0 đã được dùng để khởi tạo.
  • Trong vòng lặp, chúng ta so sánh a[i] với lonNhatnhoNhat. Nếu a[i] lớn hơn lonNhat hiện tại, lonNhat được cập nhật. Tương tự với nhoNhat.
  • Đoạn code in mảng sử dụng vòng lặp range-based for loop (for (int gt : a)), đây là cách gọn gàng để duyệt qua tất cả các phần tử của container như vector.

Bài tập 4: Đếm số lần xuất hiện của một giá trị

Yêu cầu bài toán: Cho một mảng và một giá trị cụ thể. Đếm xem giá trị đó xuất hiện bao nhiêu lần trong mảng.

Ý tưởng giải quyết:

  • Duyệt qua tất cả các phần tử trong mảng.
  • Sử dụng một biến đếm, khởi tạo bằng 0.
  • Trong mỗi lần lặp, so sánh phần tử hiện tại với giá trị cần đếm. Nếu chúng bằng nhau, tăng biến đếm lên 1.

Mã nguồn minh họa:

#include <iostream>
#include <vector>

int main() {
    using namespace std;
    vector<int> a = {1, 5, 3, 5, 2, 5, 8, 5};
    int giaTri = 5;

    int soLan = 0;
    for (size_t i = 0; i < a.size(); ++i) {
        if (a[i] == giaTri) {
            soLan++;
        }
    }

    cout << "Mang: ";
    for (int gt : a) {
         cout << gt << " ";
    }
    cout << endl;

    cout << "So lan xuat hien cua gia tri " << giaTri << " la: " << soLan << endl;

    return 0;
}

Output ví dụ:

Mang: 1 5 3 5 2 5 8 5
So lan xuat hien cua gia tri 5 la: 4

Giải thích code:

  • Chúng ta khai báo vector<int> a và biến giaTri là giá trị chúng ta muốn đếm.
  • Biến soLan được khởi tạo bằng 0 để bắt đầu đếm.
  • Vòng lặp for (size_t i = 0; i < a.size(); ++i) duyệt qua từng phần tử.
  • Trong vòng lặp, điều kiện if (a[i] == giaTri) kiểm tra xem phần tử hiện tại có bằng giá trị mục tiêu không.
  • Nếu bằng, soLan++ tăng biến đếm lên 1.

Bài tập 5: Sắp xếp mảng

Yêu cầu bài toán: Sắp xếp các phần tử trong mảng theo thứ tự tăng dần.

Ý tưởng giải quyết: Mặc dù có nhiều thuật toán sắp xếp khác nhau (như Bubble Sort, Selection Sort, Merge Sort...), cách đơn giản nhấthiệu quả nhất trong C++ là sử dụng hàm sắp xếp có sẵn trong thư viện chuẩn (sort).

Mã nguồn minh họa:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    using namespace std;
    vector<int> a = {12, 4, 9, 2, 18, 7};

    cout << "Mang truoc khi sap xep: ";
    for (int gt : a) {
         cout << gt << " ";
    }
    cout << endl;

    sort(a.begin(), a.end());

    cout << "Mang sau khi sap xep tang dan: ";
    for (int gt : a) {
         cout << gt << " ";
    }
    cout << endl;

    return 0;
}

Output ví dụ:

Mang truoc khi sap xep: 12 4 9 2 18 7
Mang sau khi sap xep tang dan: 2 4 7 9 12 18

Giải thích code:

  • Chúng ta bao gồm thư viện <algorithm> chứa hàm sort.
  • sort(a.begin(), a.end()); là lời gọi hàm sắp xếp. a.begin()a.end() là các iterator xác định phạm vi cần sắp xếp (từ đầu đến cuối vector).
  • Mặc định, sort sắp xếp các phần tử theo thứ tự tăng dần. Nó thay đổi trực tiếp (in-place) vector a.
  • Sau khi gọi sort, vector a đã được sắp xếp. Vòng lặp for-each được sử dụng để in ra mảng đã sắp xếp.

Bài tập 6: Tìm kiếm một giá trị trong mảng (Linear Search)

Yêu cầu bài toán: Kiểm tra xem một giá trị cụ thể có tồn tại trong mảng hay không. Nếu có, cho biết nó xuất hiện lần đầu tiên tại chỉ số nào.

Ý tưởng giải quyết: Phương pháp tìm kiếm đơn giản nhất là tìm kiếm tuyến tính (Linear Search):

  • Duyệt qua từng phần tử của mảng từ đầu đến cuối.
  • So sánh phần tử hiện tại với giá trị cần tìm.
  • Nếu tìm thấy, ta biết giá trị đó tồn tại và có thể trả về chỉ số hiện tại rồi kết thúc tìm kiếm.
  • Nếu duyệt hết mảng mà không tìm thấy, giá trị đó không tồn tại trong mảng.

Mã nguồn minh họa:

#include <iostream>
#include <vector>

int main() {
    using namespace std;
    vector<int> a = {15, 8, 22, 10, 5, 22, 30};
    int timGT = 22;
    int khongCoGT = 99;

    cout << "Mang: ";
    for (int gt : a) {
         cout << gt << " ";
    }
    cout << endl;

    int viTri = -1;
    for (size_t i = 0; i < a.size(); ++i) {
        if (a[i] == timGT) {
            viTri = i;
            break;
        }
    }

    if (viTri != -1) {
        cout << "Gia tri " << timGT << " duoc tim thay lan dau tien tai chi so: " << viTri << endl;
    } else {
        cout << "Gia tri " << timGT << " khong ton tai trong mang." << endl;
    }

    viTri = -1; // Reset viTri cho lan tim kiem tiep theo
    for (size_t i = 0; i < a.size(); ++i) {
        if (a[i] == khongCoGT) {
            viTri = i;
            break;
        }
    }
    if (viTri != -1) {
        cout << "Gia tri " << khongCoGT << " duoc tim thay lan dau tien tai chi so: " << viTri << endl;
    } else {
        cout << "Gia tri " << khongCoGT << " khong ton tai trong mang." << endl;
    }

    return 0;
}

Output ví dụ:

Mang: 15 8 22 10 5 22 30
Gia tri 22 duoc tim thay lan dau tien tai chi so: 2
Gia tri 99 khong ton tai trong mang.

Giải thích code:

  • Chúng ta khai báo vector<int> a, timGT (giá trị tìm thấy) và khongCoGT (giá trị không tìm thấy).
  • Biến viTri được khởi tạo bằng -1. Chúng ta dùng -1 như một chỉ báo rằng giá trị chưa được tìm thấy.
  • Vòng lặp for (size_t i = 0; i < a.size(); ++i) duyệt qua từng phần tử.
  • if (a[i] == timGT) kiểm tra xem phần tử hiện tại có bằng giá trị cần tìm không.
  • Nếu có, chúng ta gán i vào viTri và sử dụng break; để thoát khỏi vòng lặp ngay lập tức (vì yêu cầu là tìm lần đầu tiên xuất hiện). Nếu không có break;, nó sẽ tiếp tục duyệt và viTri sẽ lưu chỉ số của lần xuất hiện cuối cùng.
  • Sau vòng lặp, chúng ta kiểm tra giá trị của viTri. Nếu nó vẫn là -1, tức là không tìm thấy. Ngược lại, viTri chứa chỉ số của lần xuất hiện đầu tiên.
  • Đoạn code được lặp lại để minh họa cả trường hợp tìm thấy và không tìm thấy giá trị.

Comments

There are no comments at the moment.