Bản đồ trong C++ Thư viện mẫu chuẩn (STL)

⚡ Tóm tắt thông minh

Bản đồ trong C++ Đây là một container liên kết từ Thư viện mẫu chuẩn (Standard Template Library) lưu trữ các phần tử dưới dạng các cặp khóa-giá trị được sắp xếp, trong đó mỗi khóa duy nhất ánh xạ tới một giá trị và cho phép tìm kiếm, chèn và duyệt theo thứ tự nhanh chóng.

  • 4 Thùng chứa liên kết: A C++ Map lưu trữ các mục dưới dạng cặp khóa-giá trị với các khóa duy nhất, được sắp xếp tự động.
  • 🧩 Tiêu đề và cú pháp: Bao gồm phần khai báo map, sau đó khai báo std::map Tên dùng để lưu trữ các cặp kiểu dữ liệu.
  • 🛠️ Chức năng tích hợp sẵn: Các phương thức begin(), size(), empty(), insert(), find(), erase() và clear() quản lý nội dung của map.
  • 🔄 Lặp lại: Trình lặp hai chiều duyệt qua các phần tử của bản đồ theo thứ tự khóa đã được sắp xếp để đọc hoặc xóa.
  • 🔑 Khóa duy nhất: Hai phần tử không thể dùng chung một khóa, điều này khiến map trở nên lý tưởng như một mảng liên kết.
  • 🤖 Hỗ trợ AI: GitHub Copilot và các trợ lý AI tương tự có thể tạo cấu trúc khai báo bản đồ và vòng lặp từ một đoạn chú thích ngắn.

Bản đồ trong C++ STL

Bản đồ trong đó là gì C++?

In C++MAP là một cấu trúc dữ liệu liên kết lưu trữ các mục dưới dạng ánh xạ. Mỗi mục trong bản đồ bao gồm một giá trị khóa và một giá trị được ánh xạ. Hai giá trị được ánh xạ không thể có cùng giá trị khóa.

Các giá trị khóa hữu ích cho việc sắp xếp và xác định các phần tử một cách duy nhất, trong khi các giá trị được ánh xạ lưu trữ nội dung liên kết với mỗi khóa. Hai loại này có thể khác nhau về kiểu dữ liệu, nhưng kiểu thành viên kết hợp chúng thành một cặp chứa cả hai.

Trước khi viết bất kỳ đoạn mã nào, việc hiểu tại sao map thường là container phù hợp để sử dụng là điều rất hữu ích.

Tại sao nên sử dụng std::map?

Dưới đây là những lý do nên sử dụng bản đồ:

  • std::map chỉ lưu trữ các khóa duy nhất, được sắp xếp theo thứ tự dựa trên tiêu chí sắp xếp đã chọn.
  • Việc tìm kiếm các phần tử bằng khóa rất dễ dàng và nhanh chóng.
  • Chỉ có một phần tử được gắn vào mỗi khóa.
  • std::map có thể được sử dụng như một mảng kết hợp.
  • std::map có thể được triển khai bằng cách sử dụng cây nhị phân cân bằng.

Để tận dụng những lợi ích này, hãy bắt đầu với cú pháp khai báo.

cú pháp

Để khai báo std::map, hãy sử dụng cú pháp sau:

std::map<key_datatype, value_datatype>map_name; 
  • kiểu dữ liệu khóa biểu thị kiểu dữ liệu của các phím bản đồ.
  • kiểu dữ liệu giá trị biểu thị kiểu dữ liệu của các giá trị tương ứng với các khóa bản đồ.
  • tên bản đồ là tên của bản đồ.

Ví dụ:

map<string, int> my_map; 

Chúng ta đã khai báo một map có tên là my_map. Map này sẽ có kiểu dữ liệu khóa là chuỗi và kiểu dữ liệu giá trị là số nguyên.

Các loại thành viên

Các hàm thành viên có thể sử dụng các kiểu thành viên sau đây làm tham số hoặc kiểu trả về:

  • loại chính: Khóa (tham số đầu tiên trong mẫu)
  • ánh xạ_type: T (tham số thứ hai trong mẫu)
  • key_compare: So sánh (tham số thứ ba trong mẫu)
  • phân bổ_type: Alloc (tham số thứ tư trong mẫu)
  • giá trị_type: đôi
  • giá trị_so sánh: Lớp hàm lồng nhau để so sánh các phần tử
  • tài liệu tham khảo: allocator_type::reference
  • const_reference: allocator_type::const_reference
  • con trỏ: allocator_type::con trỏ
  • const_pointer: allocator_type::const_pointer
  • vòng lặp: một trình vòng lặp hai chiều tới value_type
  • const_iterator: một trình vòng lặp hai chiều tới const value_type
  • đảo ngược_iterator: một trình vòng lặp ngược
  • const_reverse_iterator: một trình vòng lặp ngược không đổi
  • sự khác biệt_type: ptrdiff_t
  • kích thước_type: kích thước_t

Các hàm tích hợp của std::map

std::map đi kèm với các chức năng sẵn có. Một số trong số này bao gồm:

  • bắt đầu () – Hàm này trả về con trỏ đến phần tử đầu tiên của bản đồ.
  • kích thước() – Hàm này trả về số lượng phần tử trong một bản đồ.
  • trống() – Hàm này trả về giá trị Boolean cho biết liệu bản đồ có rỗng hay không.
  • chèn(cặp(khóa, giá trị)) – Chức năng này chèn một cặp khóa-giá trị mới vào bản đồ.
  • tìm(val) – Hàm này trả về con trỏ đến phần tử `val` nếu tìm thấy. Nếu không, nó trả về `m.end()`.
  • xóa (vị trí lặp) – Chức năng này xóa phần tử tại vị trí được trỏ bởi con trỏ lặp.
  • xóa(const g) – Chức năng này xóa cặp khóa-giá trị g khỏi một map.
  • thông thoáng() – Chức năng này xóa tất cả các mục khỏi bản đồ.

Sau khi các hàm đã được định nghĩa, các ví dụ sau đây sẽ minh họa cách sử dụng chúng, bắt đầu bằng phép lặp.

Lặp lại các phần tử bản đồ

Bạn có thể lặp qua các phần tử của bản đồ. Chúng ta chỉ cần tạo một trình lặp và sử dụng nó cho việc này. Ví dụ:

Ví dụ 1

#include <iostream>
#include <string>
#include <map> 

using namespace std;
int main() {

	map<int, string> Students;

	Students.insert(std::pair<int, string>(200, "Alice"));

	Students.insert(std::pair<int, string>(201, "John"));

	cout << "Map size is: " << Students.size() << endl;

	cout << endl << "Default map Order is: " << endl;

	for (map<int, string>::iterator it = Students.begin(); it != Students.end(); ++it) {

		cout << (*it).first << ": " << (*it).second << endl;
	}
}

Đầu ra:

C++ Ví dụ 1 về kết quả của quá trình lặp bản đồ

Đây là ảnh chụp màn hình của mã:

C++ Ví dụ mã 1 về vòng lặp map

Code Giải thích:

  1. Đưa tệp tiêu đề iostream vào mã của chúng tôi để sử dụng các chức năng của nó.
  2. Đưa tệp tiêu đề chuỗi vào mã của chúng tôi để sử dụng các chức năng của nó.
  3. Đưa tệp tiêu đề bản đồ vào mã của chúng tôi để sử dụng các chức năng của nó.
  4. Bao gồm không gian tên std vào mã của chúng tôi để sử dụng các lớp của nó mà không cần gọi nó.
  5. Gọi hàm main(). { đánh dấu sự bắt đầu của phần thân hàm.
  6. Tạo một bản đồ có tên là Học sinh trong đó các khóa sẽ là số nguyên và các giá trị sẽ là chuỗi.
  7. Chèn giá trị vào bản đồ Học sinh. Khóa 200 và giá trị Alice sẽ được chèn vào bản đồ.
  8. Chèn giá trị vào bản đồ Học sinh. Khóa 201 và giá trị John sẽ được chèn vào bản đồ.
  9. Sử dụng hàm size() để lấy kích thước của bản đồ có tên Học sinh. Điều này sẽ trả về 2.
  10. In một số văn bản trên bảng điều khiển.
  11. Sử dụng vòng lặp for để tạo một trình vòng lặp được đặt tên là nó để lặp qua các phần tử của bản đồ có tên là Học sinh.
  12. In các giá trị của bản đồ Học sinh trên bảng điều khiển.
  13. Kết thúc phần thân của vòng lặp for.
  14. Phần cuối của hàm main().

Chèn dữ liệu vào std::map

Bạn có thể nhập các mục vào std::map bằng hàm Insert(). Hãy nhớ rằng các phím std::map phải là duy nhất.

Vì vậy, trước tiên nó kiểm tra xem mỗi khóa có tồn tại trong bản đồ hay không. Nếu có, mục nhập sẽ không được chèn vào, nhưng nó sẽ trả về trình lặp cho mục nhập hiện có. Nếu không có, mục nhập sẽ được chèn vào.

Hàm này có các biến thể sau:

  • chèn (cặp) – Với biến thể này, một cặp khóa-giá trị được chèn vào bản đồ.
  • chèn(start_itr, end_itr) – Với biến thể này, các mục sẽ được chèn vào trong phạm vi được xác định bởi start_itr và end_itr từ một bản đồ khác.

Hàm insert_or_assign() hoạt động tương tự như hàm insert(), nhưng nếu khóa được cung cấp đã tồn tại trong map, giá trị của nó sẽ được sửa đổi.

Ví dụ 2

#include <map>
#include <iostream>

using namespace std;

int main() {

	map<int, int> m{ {1,3} , {2,4} , {3,5} };

	m.insert({ 5, 6 });
	m.insert({ 1, 8 });

	m.insert_or_assign(1, 6);  
	
	cout << "Key\tElement\n";
	for (auto itr = m.begin(); itr != m.end(); ++itr) {
		cout << itr->first << '\t' << itr->second << '\n';
	}
	return 0;
}

Đầu ra:

C++ Ví dụ chèn bản đồ 2 đầu ra

Đây là ảnh chụp màn hình của mã:

C++ Chèn bản đồ Ví dụ 2 mã

Code Giải thích:

  1. Đưa tệp tiêu đề bản đồ vào mã của chúng tôi để sử dụng các chức năng của nó.
  2. Đưa tệp tiêu đề iostream vào mã của chúng tôi để sử dụng các chức năng của nó.
  3. Bao gồm không gian tên std vào mã của chúng tôi để sử dụng các lớp của nó mà không cần gọi nó.
  4. Gọi hàm main(). { đánh dấu sự bắt đầu của phần thân hàm.
  5. Tạo một bản đồ có tên m trong đó các khóa sẽ là số nguyên và các giá trị sẽ là số nguyên. Ba mục đã được đưa vào bản đồ.
  6. Chèn một mục mới vào bản đồ m. Khóa 5 và giá trị 6 sẽ được chèn vào bản đồ.
  7. Đang cố gắng thực hiện một mục nhập vào một khóa đã có sẵn. Vì khóa 1 đã tồn tại trên bản đồ nên việc nhập sẽ không được thực hiện.
  8. Sử dụng hàm Insert_or_signed() để chèn hoặc sửa đổi mục nhập hiện có. Vì khóa 1 đã tồn tại nên giá trị của nó sẽ được thay đổi thành 6.
  9. In một số văn bản trên bảng điều khiển. Ký tự “\t” tạo khoảng trắng theo chiều ngang trong khi ký tự “\n” di chuyển con trỏ chuột sang dòng tiếp theo.
  10. Sử dụng vòng lặp for để tạo một trình lặp có tên itr để lặp qua các phần tử của bản đồ có tên là m.
  11. In các giá trị của bản đồ m trên bảng điều khiển. Ký tự “\t” tạo khoảng trắng theo chiều ngang giữa mỗi khóa và giá trị tương ứng của nó. Ngược lại, ký tự “\n” di chuyển con trỏ chuột sang dòng tiếp theo sau mỗi lần lặp.
  12. Kết thúc phần thân của vòng lặp for.
  13. Chương trình phải trả về một giá trị sau khi hoàn thành thành công.
  14. Phần cuối của hàm main().

Tìm kiếm trong bản đồ

Chúng ta có thể sử dụng hàm `find()` để tìm kiếm các phần tử trong một map dựa trên khóa của chúng. Nếu không tìm thấy khóa, hàm sẽ trả về `std::map::end`. Ngược lại, một iterator của phần tử được tìm kiếm sẽ được trả về.

Ví dụ 3

#include <iostream>
#include <string>
#include <map> 
using namespace std;
int main() {
	map<int, string> Students;
	Students.insert(std::pair<int, string>(200, "Alice"));
	Students.insert(std::pair<int, string>(201, "John"));
	std::map<int, string>::iterator it = Students.find(201);
	if (it != Students.end()) {
		std::cout << endl << "Key 201 has the value: => "<< Students.find(201)->second << '\n';
	}
}

Đầu ra:

C++ Ví dụ 3 về kết quả tìm kiếm bản đồ

Đây là ảnh chụp màn hình của mã:

C++ Ví dụ mã tìm kiếm bản đồ 3

Code Giải thích:

  1. Đưa tệp tiêu đề iostream vào mã của chúng tôi để sử dụng các chức năng của nó mà không gặp lỗi.
  2. Đưa tệp tiêu đề chuỗi vào mã của chúng tôi để sử dụng các chức năng của nó mà không gặp lỗi.
  3. Đưa tệp tiêu đề bản đồ vào mã của chúng tôi để sử dụng các chức năng của nó mà không gặp lỗi.
  4. Bao gồm không gian tên std vào mã của chúng tôi để sử dụng các lớp của nó mà không cần gọi nó.
  5. Gọi hàm main(). { Đánh dấu sự bắt đầu phần thân của hàm main().
  6. Tạo bản đồ có tên Học sinh có khóa sẽ là chuỗi số nguyên và giá trị.
  7. Chèn giá trị vào bản đồ Học sinh. Khóa 200 và giá trị Alice sẽ được chèn vào bản đồ.
  8. Chèn giá trị vào bản đồ Học sinh. Khóa 201 và giá trị John sẽ được chèn vào bản đồ.
  9. Tìm giá trị liên quan đến khóa 201.
  10. Sử dụng câu lệnh if để kiểm tra xem giá trị của khóa có được tìm thấy hay không.
  11. In giá trị của khóa cùng với một số văn bản trên bảng điều khiển.
  12. Kết thúc phần thân của câu lệnh if.
  13. Phần cuối của hàm main().

Xóa dữ liệu khỏi bản đồ

Chúng ta có thể sử dụng hàm erase() để xóa một giá trị khỏi bản đồ. Chúng ta chỉ cần tạo một trình vòng lặp trỏ đến phần tử cần xóa. Trình vòng lặp sau đó được chuyển tới hàm eras().

Ví dụ 4

#include <iostream>
#include <string>
#include <map>

using namespace std;
int main() {

	map<std::string, int> my_map;

	my_map.insert(std::make_pair("cow", 1));

	my_map.insert(std::make_pair("cat", 2));

	my_map["lion"] = 3;

	map<std::string, int>::iterator it = my_map.find("cat");

	my_map.erase(it);

	for (map<string, int>::iterator it = my_map.begin(); it != my_map.end(); ++it)

		cout << (*it).first << ": " << (*it).second << endl;

  return 0;
}

Đầu ra:

C++ Ví dụ 4 đầu ra: map erase delete

Đây là ảnh chụp màn hình của mã:

C++ map erase delete Ví dụ 4 mã

Code Giải thích:

  1. Đưa tệp tiêu đề iostream vào mã của chúng tôi để sử dụng các chức năng của nó.
  2. Đưa tệp tiêu đề chuỗi vào mã của chúng tôi để sử dụng các chức năng của nó.
  3. Đưa tệp tiêu đề bản đồ vào mã của chúng tôi để sử dụng các chức năng của nó.
  4. Bao gồm không gian tên std vào mã của chúng tôi để sử dụng các lớp của nó mà không cần gọi nó.
  5. Gọi hàm main(). { Đánh dấu sự bắt đầu phần thân của hàm main().
  6. Tạo bản đồ có tên my_map có khóa sẽ là chuỗi và giá trị số nguyên.
  7. Chèn giá trị vào bản đồ my_map. Khóa Cow và giá trị 1 sẽ được chèn vào bản đồ.
  8. Chèn giá trị vào bản đồ my_map. Một khóa Cat và giá trị 2 sẽ được chèn vào bản đồ.
  9. Thêm giá trị 3 vào bản đồ my_map bằng phím sư tử.
  10. Tạo một trình lặp để lặp qua bản đồ my_map để tìm key cat.
  11. Xóa phần tử được trỏ bởi iterator.
  12. Sử dụng một iterator để duyệt qua các phần tử của map my_map từ đầu đến cuối.
  13. In nội dung của bản đồ my_map trên bảng điều khiển.
  14. Chương trình phải trả về đầu ra sau khi hoàn thành thành công.
  15. Phần cuối của hàm main().

Câu Hỏi Thường Gặp

std::map giữ các khóa được sắp xếp bằng cách sử dụng cây tìm kiếm nhị phân tự cân bằng, cho độ phức tạp O(log n) thao tác. std::unordered_map sử dụng bảng băm cho độ phức tạp tìm kiếm trung bình O(1) nhưng lưu trữ các khóa không theo thứ tự cụ thể nào. Hãy chọn dựa trên nhu cầu sắp xếp của bạn.

Lớp `std::map` thường được triển khai dưới dạng cây tìm kiếm nhị phân tự cân bằng, phổ biến nhất là cây đỏ đen. Điều này giúp giữ các khóa theo thứ tự đã sắp xếp và đảm bảo thời gian thực hiện thao tác chèn, xóa và tìm kiếm là logarit.

Không. Kiểu dữ liệu std::map chỉ chứa các khóa duy nhất, vì vậy việc chèn một khóa đã tồn tại sẽ không ghi đè lên khóa đó. Khi cần các khóa trùng lặp, hãy sử dụng std::multimap, cho phép nhiều phần tử chia sẻ cùng một giá trị khóa.

Sử dụng map_name[key] để đọc hoặc gán giá trị; toán tử chỉ số sẽ chèn một mục mặc định nếu khóa bị thiếu. Thành viên at() sẽ ném ra một ngoại lệ đối với các khóa bị thiếu, do đó đây là lựa chọn an toàn hơn.

Truyền một bộ so sánh tùy chỉnh làm đối số mẫu thứ ba, chẳng hạn như std::map >. Bộ so sánh lớn hơn sắp xếp các khóa từ cao nhất đến thấp nhất thay vì thứ tự tăng dần mặc định.

Kiểu dữ liệu `std::map` lưu trữ các cặp khóa-giá trị và tìm kiếm giá trị theo khóa, trong khi `std::set` chỉ lưu trữ các khóa duy nhất mà không có giá trị liên kết. Cả hai đều giữ cho các phần tử được sắp xếp, nhưng `map` liên kết dữ liệu với mỗi khóa.

Đúng vậy. Trợ lý lập trình AI có thể chuyển một lời nhắc ngắn hoặc bình luận thành mã std::map hoạt động, bao gồm cả khai báo, lệnh chèn và vòng lặp lặp. Luôn luôn xem xét các kiểu khóa được tạo ra, thứ tự và các trường hợp ngoại lệ trước khi biên dịch.

Vâng. Trợ lý GitHub Công cụ này gợi ý việc khai báo bản đồ, các lệnh chèn và tìm kiếm, cũng như các vòng lặp khi bạn gõ. Nó xử lý tốt các đoạn mã lặp đi lặp lại, mặc dù bạn vẫn nên kiểm tra tính duy nhất của khóa và logic trước khi biên dịch.

Tóm tắt bài viết này với: