C++: map

Giới thiệu

Các lớp vector, list thuộc cấu trúc Sequence Containers (cấu trúc tuần tự), riêng với lớp map thuộc 1 cấu trúc khác đó là Associative Containers (cấu trúc liên kết), là kiểu dữ liệu cho phép quản lý 1 cặp key/value – khóa và giá trị, nghĩa là muốn xác định được nội dung value thì phải biết được vị trí key mà map đang quản lý.

Nếu như lớp map quản lý cặp đối tượng key/value, vậy đối tượng nào sinh ra được cặp đối tượng đó. Để sinh ra cặp đối tượng key/value cần sử dụng lớp pair, lớp pair nằm  trong thư viện utility. Trước khi tìm hiểu về lớp map cần biết về lớp pair.

Lớp pair

pair cho phép gộp 2 đối tượng thành 1 cặp, 2 đối tượng có thẻ cùng kiểu hoặc khác kiểu, với thuộc tính first là key và second là value.

Cú pháp khai báo:

pair<valueType1, valueType2> variableName;

Ví dụ: pair<string, string> dictionary;

pair có các constructor như:

  • default constructor
  • copy constructor
  • initialization constructor

Ví dụ:

// default constructor
pair<int, char*> defaultPair;

// initialization constructor
pair<int, char*> initPair(0, "a");

// copy constructor
pair<int, char*> copyPair(pair1);

Lớp pair có các thuộc tính first và second cho phép lấy dữ liệu

pair<string, string> word("eat", "an");
cout << word.first << " " << word.second;

Lớp map

Lớp map nằm trong thư viện map vì vậy muốn sử dụng trước tiên phải #include<map>.

Cú pháp khai báo:

map<valueType1, valueType2> variableName;

Ví dụ:

map<string, string> dictionary;
dictionary["eat"] = "an";
dictionary["sleep"] = "ngu";

Biến dictionary được khai báo với cặp dữ liệu là <string, string>, vì vậy:

  • key của dictionary phải là kiểu string – “eat” “sleep”…
  • value của dictionary phải là kiểu string – “an” “ngu”…

Lớp map cũng giống như những lớp vector, list đều được định nghĩa các hàm thành viên hỗ trợ cho việc truy xuất, lấy kích thước, các constructor đã được override, …

Các phương thức thường dùng trong map

Constructor

Cũng giống với những lớp vector, lớp map cũng có:

  • default constructor
  • ranger constructor
  • copy constructor.

Các hàm thành viên này hoạt động hoàn toàn giống với lớp vector, list.

Ví dụ:

// default constructor
map<char, int> character0;

character0['a'] = 97;
character0['b'] = 98;
character0['c'] = 99;
character0['d'] = 100;

// range constructor
map<char, int> character1(character0.begin(), character0.end());

// copy constructor
map<char, int> character2(character1);

Ngoài ra còn có operator= cho phép các lớp map có thể sao chép nội dung cấu trúc dữ liệu với nhau.

map<int, char*> map0, map1;
map0[0] = "a";
map0[1] = "b";

map1 = map0;

Duyệt map

Lớp map quản lý value bằng key, nếu trường hợp quên map thì làm sao có thể truy xuất để lấy dữ liệu value. Để giải quyết vấn đề trên trong lớp map định nghĩa thao tác iterators cho phép truy xuất đến phần tử trong map để lấy dữ liệu value và key cần thiết. Có các iterators đã được cung cấp như: begin(), end(), rbegin(), rend(), … chúng hoạt động như nhau nhưng chỉ khác phần tử truy cập ở vị trí nào trong lớp map.

Ví dụ:

map<int, char*> texes;
texts[0] = "ab";
texts[1] = "bc";
texts[0] = "cd";

map<int, char*>::iterator i;

for (i = texts.begin(); i != texts.end(); i++)
	cout << *i << endl;

// output (0, "cd"), (1, "bc")

Kết quả tại sao không phải là: (0, “ab”) (1, “bc”)  hay (0, “ab”) (1, “bc”) (0, “cd”), … đó là do trong lớp map quy định key chỉ được tồn tại duy nhất (không được trùng), vì vậy khi khai báo ở dòng texts[0] = “cd”; sẽ làm thay đổi dữ liệu của texts[0] từ “ab” thành “cd”.

size() để lấy kích thước của map

size() cho phép lấy kích thước của map.

Ví dụ:

map<int, char*> mymap, copymymap;
mymap[0] = "a";
mymap[1] = "b";
mymap[0] = "c";

cout << mymap.size();

empty để kiểm tra map có rỗng hay không

empty() cho phép kiểm tra map có rỗng hay không?

Ví dụ:

map<int, char*> mymap, copymymap;
mymap[0] = "a";
mymap[1] = "b";
mymap[0] = "c";

if (copymymap.empty()) cout << "copymymap is empty";

Truy xuất theo chỉ số với at(index)

[index] hay at(index) cho phép truy xuất trực tiếp đến key của từng phần tử.

map<int, char*> mymap, copymymap;
mymap[0] = "a";
mymap[1] = "b";

cout << mymap[1] << " " << mymap.at(0);

insert() để thêm dữ liệu vào map

insert() cho phép chèn thêm 1 đối tượng.

Ví dụ:

map<int, char*> mymap, copymymap;
mymap[0] = "a";
mymap[1] = "b";
mymap[5] = "c";

// chèn vào copymymap cặp đối tượng (10, "c")	
copymymap.insert(pair<int, char*>(10, "c"));

// chèn (-1, "d") vào copymymap từ vị trí bắt đầu của copymymap
copymymap.insert(copymymap.begin(), pair<int, char*>(-1, "d"));

// chèn mymap vào copymymap
copymymap.insert(mymap.begin(), mymap.end());

// => copymymap = {(-1,"d"),(0,"a"),(1,"b"),(5,"c"),(10,"c")}

Lưu ý việc chèn ở vị trí nào thật ra là vô nghĩa, vì vị trí của nó phụ thuộc vào key trong cặp đối tượng “key/ value”, trong ví dụ trên thì “key” là kiểu số nguyên vì vậy vị trí của các cặp đối tượng key/value sẽ được xác định theo các key sắp xếp tăng dần.

Tìm kiếm phần tử với find()

find() cho phép tìm kiếm theo key của cặp giá trị key/value

Ví dụ:

map<int, char*> mymap;
mymap[0] = "a";
mymap[1] = "b";
mymap[5] = "c";
mymap[9] = "e";
map<int, char*>::iterator var = mymap.find(5);
// var -> (5,"c")

erase() để xóa bỏ 1 phần tử trong map

erase() cho phép xóa 1 phần tử.

Ví dụ:

map<int, char*> mymap, copymymap;
mymap[0] = "a";
mymap[1] = "b";
mymap[5] = "c";
mymap[7] = "d";
mymap[9] = "e";

// xóa cặp đối tượng với "key" là 5
mymap.erase(5);		
// => mymap =  {(0,"a"),(1,"b"),(7,"d"),(9,"e")}
	
map<int, char*>::iterator var = mymap.begin();
// xóa cặp đối tượng mà var đang truy cập
mymap.erase(var); // => mymap =  {(1,"b"),(7,"d"),(9,"e")}

var = mymap.find(7); // => var truy cập đến (7,"d")

// xóa từ vị trí var đang truy cập cho đến (9,"e") 
mymap.erase(var, mymap.end()); // => mymap = {(1,"b")}

Xóa tất cả phần tử trong map bằng clear()

clear() cho phép xóa tất cả phần tử.

Ví dụ:

map<int, char*> mymap;
mymap[0] = "a";
mymap[1] = "b";
mymap[5] = "c";
mymap[7] = "d";
mymap[9] = "e";

mymap.clear();		
// => mymap =  {}

swap() để hoán đổi nội dung 2 map

swap() cho phép hoán đổi nội dung của 2 map.

Ví dụ:

map<char,int> map1, map2;

map1['x'] = 100;
map1['y'] = 200;

map2['a'] = 11;
map2['b'] = 22;
map2['c'] = 33;

map1.swap(map2);
// => map1 = {("x",11),("b",22),("c",33)}
// => map2 = {("x",100),("y",200)}