Xóa giá trị trùng lặp trong mảng bằng C, C++
Trong bài học này, bạn sẽ loại bỏ các giá trị bị lặp lại trong mảng mà vẫn giữ nguyên thứ tự xuất hiện đầu tiên.
Giới thiệu
Để loại bỏ giá trị trùng lặp mà vẫn giữ thứ tự, ta tạo một mảng kết quả riêng. Với mỗi phần tử của mảng gốc, chương trình kiểm tra phần tử đó đã có trong mảng kết quả hay chưa. Nếu chưa có thì mới thêm vào.
Những điểm quan trọng
- Luôn bật cảnh báo của trình biên dịch (compiler warning) và sửa hết các cảnh báo.
- Hiểu rõ kiểu dữ liệu và thời gian tồn tại (lifetime) của từng giá trị.
- Luôn kiểm tra dữ liệu đầu vào và giới hạn chỉ số của mảng.
Code ví dụ bằng C và C++
#include <stdio.h>
int main(void) {
int input[] = {1, 2, 1, 3, 2, 4}, output[6], size = 0;
// Keep the first occurrence of every value.
for (int i = 0; i < 6; ++i) { int seen = 0; for (int j = 0; j < size; ++j) if (output[j] == input[i]) seen = 1; if (!seen) output[size++] = input[i]; }
for (int i = 0; i < size; ++i) printf("%s%d", i ? " " : "", output[i]); puts("");
}
1 2 3 4
#include <iostream>
#include <unordered_set>
#include <vector>
int main() {
std::vector input{1, 2, 1, 3, 2, 4}; std::vector<int> output; std::unordered_set<int> seen;
// Insert returns true only for the first occurrence.
for (int value : input) if (seen.insert(value).second) output.push_back(value);
for (size_t i = 0; i < output.size(); ++i) std::cout << (i ? " " : "") << output[i]; std::cout << '\n';
}
1 2 3 4
So sánh C và C++
Vòng lặp trong kiểm tra input[i] đã xuất hiện trong output hay chưa và ghi nhận vào biến seen. Chỉ khi seen bằng 0, giá trị mới được thêm vào cuối output và size tăng lên. Kết quả là 1 2 3 4. Cách làm này dễ hiểu nhưng mất O(n²). Với dữ liệu lớn, C++ có thể dùng std::unordered_set để kiểm tra nhanh hơn.
C dùng các hàm thủ tục gọn nhẹ và thể hiện rõ cách dữ liệu được biểu diễn trong bộ nhớ.
C++ vẫn cho phép làm việc ở mức thấp nhưng bổ sung các kiểu dữ liệu thư viện và công cụ trừu tượng an toàn hơn.
Bài tập mở rộng
Hãy chạy cả hai phiên bản, sau đó thử thay đổi code để quan sát sự khác biệt về mức độ an toàn mà mỗi ngôn ngữ mang lại.
- Thử nhập dữ liệu sai và các giá trị ở biên.
- Biên dịch với các cờ -Wall -Wextra -Wpedantic để bật thêm cảnh báo.
- Tách phần khai báo dùng chung ra file header và phần cài đặt ra file riêng.
Luyện tập với thử thách
Áp dụng kiến thức của bài học này để giải một bài toán thực tế. Mỗi thử thách chạy ngay trên trình duyệt, có kiểm thử tức thì và AI nhận xét.
Tất cả thử thách