Trong bài viết này, chúng ta sẽ cùng tìm hiểu về lớp TreeMap trong Java và các phương thức của nó với sự trợ giúp của các ví dụ dẫn chứng.
Lớp TreeMap
Lớp TreeMap trong Java cung cấp việc triển khai cấu trúc dữ liệu dạng cây. Nó thực hiện triển khai NavigableMap Interface.
Tạo TreeMap
Để tạo lớp TreeMap trong Java, trước tiên chúng ta phải thêm gói package java.util.TreeMap. Và sau đây là cách chúng ta có thể tạo TreeMap trong Java.
1 |
TreeMap<Khóa, Giá trị> a = new TreeMap<>(); |
Trong đoạn mã trên, chúng ta đã tạo một TreeMap có tên là a mà không có bất kỳ đối số nào. Trong trường hợp này, các phần tử trong TreeMap được sắp xếp một cách tự nhiên (thứ tự tăng dần). Tuy nhiên, chúng ta có thể tùy chỉnh việc sắp xếp các phần tử bằng cách sử dụng Comparator Interface. Chúng ta sẽ tìm hiểu về nó ở phần sau trong bài này.
Trong đó:
- Khóa là một định danh duy nhất được sử dụng để liên kết từng phần tử (giá trị) trong Map.
- Giá trị là các phần tử được liên kết bởi các khóa trong Map.
Các phương thức của TreeMap
Lớp TreeMap cung cấp nhiều phương thức khác nhau cho phép chúng ta thực hiện các thao tác cho Map.
1. Chèn các phần tử
- Phương thức put(): Chèn ánh xạ khóa và giá trị được chỉ định (bản ghi) vào Map.
- Phương thức putAll(): Chèn tất cả các mục từ Map được chỉ định vào Map gọi phương thức này.
- Phương thức putIfAbsent(): Chèn ánh xạ khóa và giá trị được chỉ định vào Map nếu khóa được chỉ định không có trong Map.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); System.out.println(sinh_vien); TreeMap<String, Integer> sinh_vien2 = new TreeMap<>(); sinh_vien2.put("Nguyen D", 30); sinh_vien2.putAll(sinh_vien); System.out.println(sinh_vien2); } } |
Kết quả:
1 2 |
{Nguyen A=23, Nguyen B=22, Nguyen C=27} {Nguyen A=23, Nguyen B=22, Nguyen C=27, Nguyen D=30} |
2. Truy cập vào các phần tử
Ta có thể sử dụng phương thức entrySet(), keySet() và values() để truy cập vào phần tử.
- Phương thức entrySet(): Trả về một tập hợp tất cả các khóa và giá trị ánh xạ (bản ghi) của một TreeMap.
- Phương thức keySet(): Trả về một tập hợp tất cả các khóa của TreeMap.
- Phương thức values(): Trả về một tập hợp tất cả các ánh xạ của TreeMap.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); System.out.println(sinh_vien.entrySet()); System.out.println(sinh_vien.keySet()); System.out.println(sinh_vien.values()); } } |
Kết quả:
1 2 3 |
[Nguyen A=23, Nguyen B=22, Nguyen C=27] [Nguyen A, Nguyen B, Nguyen C] [23, 22, 27] |
Ta cũng có thể sử dụng phương thức get() và getOrDefault() để truy cập các phần tử.
- Phương thức get(): Trả về giá trị được liên kết với khóa được chỉ định. Trả về null nếu không tìm thấy khóa.
- Phương thức getOrDefault(): Trả về giá trị được liên kết với khóa được chỉ định. Trả về giá trị mặc định đã chỉ định nếu không tìm thấy khóa.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); int i = sinh_vien.get("Nguyen A"); System.out.println("ID sinh vien la: " + i); int j = sinh_vien.getOrDefault("Nguyen E", 34); System.out.println("ID sinh vien mac dinh la: " + j); } } |
Kết quả:
1 2 |
ID sinh vien la: 23 ID sinh vien mac dinh la: 34 |
3. Xóa các phần tử
- Phương thức remove(khóa): Trả về và xóa bản ghi được liên kết với khóa được chỉ định khỏi TreeMap.
- Phương thức remove(khóa, giá trị): Chỉ xóa bản ghi khỏi Map nếu khóa được chỉ định liên kết với giá trị được chỉ định và trả về giá trị kiểu boolean.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); int i = sinh_vien.remove("Nguyen A"); System.out.println("ID bi xoa la: " + i); boolean kq = sinh_vien.remove("Nguyen C", 5); System.out.println("ID bi xoa khong?: " + kq); } } |
Kết quả:
1 2 |
ID bi xoa la: 23 ID bi xoa khong?: false |
4. Thay thế các phần tử
- Phương thức replace(khóa, giá trị): Thay thế giá trị được ánh xạ bởi khóa được chỉ định bằng giá trị mới.
- Phương thức replace(khóa, giá trị cũ, giá trị mới): Chỉ thay thế giá trị cũ bằng giá trị mới nếu giá trị cũ đã được liên kết với khóa được chỉ định.
- Phương thức ReplaceAll(hàm): Thay thế từng giá trị của Map bằng kết quả của hàm được chỉ định.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); sinh_vien.replace("Nguyen A", 13); sinh_vien.replace("Nguyen B", 22, 12); System.out.println(sinh_vien); sinh_vien.replaceAll((key, oldValue) -> oldValue + 1); System.out.println(sinh_vien); } } |
Kết quả:
1 2 |
{Nguyen A=13, Nguyen B=12, Nguyen C=27} {Nguyen A=14, Nguyen B=13, Nguyen C=28} |
Trong đoạn mã trên, câu lệnh:
1 |
sinh_vien.replaceAll((key, oldValue) -> oldValue + 1); |
Ở đây, chúng ta đã chuyển một biểu thức lambda hay Lambda expression làm đối số. Phương thức ReplaceAll() truy cập vào tất cả các bản ghi của Map. Sau đó, nó thay thế tất cả các phần tử bằng các giá trị mới.
Các phương thức điều hướng
Vì lớp TreeMap triển khai NavigableMap nên nó cung cấp nhiều phương thức khác nhau để điều hướng qua các phần tử của TreeMap.
1. Phương thức First và Last
- Phương thức firstKey(): Trả về khóa đầu tiên của Map.
- Phương thức firstEntry(): Trả về ánh xạ của khóa và giá trị của khóa đầu tiên của Map.
- Phương thức lastKey(): Trả về khóa cuối cùng của Map.
- Phương thức lastEntry(): Trả về ánh xạ của khóa và giá trị của khóa cuối cùng của Map.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); String i = sinh_vien.firstKey(); System.out.println("Khoa dau tien: " + i); String j = sinh_vien.lastKey(); System.out.println("Khoa cuoi cung: " + j); System.out.println("Cap khoa va gia tri dau tien: " + sinh_vien.firstEntry()); System.out.println("Cap khoa va gia tri cuoi cung: " + sinh_vien.lastEntry()); } } |
Kết quả:
1 2 3 |
Khoa cuoi cung: Nguyen C Cap khoa va gia tri dau tien: Nguyen A=23 Cap khoa va gia tri cuoi cung: Nguyen C=27 |
2. Phương thức Ceiling, Floor, Higher và Lower
- Phương thức higherKey(): Trả về khóa thấp nhất trong số các khóa lớn hơn khóa được chỉ định.
- Phương thức higherEntry(): Trả về một bản ghi được liên kết với một khóa thấp nhất trong số tất cả các khóa lớn hơn khóa được chỉ định.
- Phương thức lowerKey(): Trả về khóa lớn nhất trong số tất cả các khóa nhỏ hơn khóa được chỉ định.
- Phương thức lowerEntry(): Trả về một bản ghi được liên kết với khóa lớn nhất trong số tất cả các khóa nhỏ hơn khóa được chỉ định.
- Phương thức ceilingKey(): Trả về khóa thấp nhất trong số các khóa lớn hơn khóa được chỉ định. Nếu khóa được truyền dưới dạng đối số có trong Map, nó sẽ trả về khóa đó.
- Phương thức ceilingEntry(): Trả về một bản ghi được liên kết với một khóa thấp nhất trong số những khóa lớn hơn khóa được chỉ định. Nếu một bản ghi được liên kết với khóa được truyền làm đối số có trong Map, nó sẽ trả về bản ghi được liên kết với khóa đó.
- Phương thức floorKey(): Trả về khóa lớn nhất trong số các khóa nhỏ hơn khóa được chỉ định. Nếu khóa được truyền làm đối số tồn tại trong Map, nó sẽ trả về khóa đó.
- Phương thức floorEntry(): Trả về một bản ghi được liên kết với khóa lớn nhất trong số các khóa nhỏ hơn khóa được chỉ định. Nếu khóa được truyền làm đối số đã tồn tại, nó sẽ trả về khóa đó.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); System.out.println(sinh_vien.higherKey("Nguyen A")); System.out.println(sinh_vien.higherEntry("Nguyen A")); System.out.println(sinh_vien.ceilingEntry("Nguyen A")); System.out.println(sinh_vien.floorKey("Nguyen A")); System.out.println(sinh_vien.floorEntry("Nguyen A")); } } |
Kết quả:
1 2 3 4 5 |
Nguyen B Nguyen B=22 Nguyen A=23 Nguyen A Nguyen A=23 |
3. Phương thức pollFirstEntry() và pollLastEntry()
- Phương thức pollFirstEntry(): Trả về và xóa bản ghi được liên kết với khóa đầu tiên của Map.
- Phương thức pollLastEntry(): Trả về và xóa bản ghi được liên kết với khóa cuối cùng của Map.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); System.out.println(sinh_vien.pollFirstEntry()); System.out.println(sinh_vien.pollLastEntry()); System.out.println(sinh_vien); } } |
Kết quả:
1 2 3 |
Nguyen A=23 Nguyen C=27 {Nguyen B=22} |
4. Phương thức headMap(), tailMap() và subMap()
Phương thức headMap(khóa, giá trị kiểu boolean)
- Phương thức headMap() trả về tất cả các cặp khóa và giá trị của một TreeMap trước khóa được chỉ định (được truyền dưới dạng đối số).
- Tham số thứ 2 là tùy chọn. Giá trị mặc định của nó là false. Nếu true được truyền, phương thức này bao gồm cặp khóa và giá trị của khóa được chỉ định truyền làm đối số.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); System.out.println(sinh_vien.headMap("Nguyen A",true)); } } |
Kết quả:
1 |
{Nguyen A=23} |
Phương thức tailMap (khóa, giá trị kiểu boolean)
- Phương thức tailMap() trả về tất cả các cặp khóa và giá trị của một TreeMap bắt đầu từ khóa được chỉ định (được truyền dưới dạng đối số).
- Tham số thứ 2 là một tham số tùy chọn. Giá trị mặc định của nó là true. Nếu false được truyền, phương thức này không bao gồm cặp khóa và giá trị của khóa được chỉ định.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); System.out.println(sinh_vien.tailMap("Nguyen A",false)); } } |
Kết quả:
1 |
{Nguyen B=22, Nguyen C=27} |
Phương thức subMap (k1, bV1, k2, bV2)
- Phương thức subMap() trả về tất cả các bản ghi được liên kết với các khóa giữa k1 và k2 bao gồm cả bản ghi của k1.
- bV1 và bV2 là các tham số kiểu boolean tùy chọn. Giá trị mặc định của bV1 là true và giá trị mặc định của bV2 là false.
- Nếu false được truyền cho bV1, phương thức trả về tất cả các bản ghi được liên kết với các khóa giữa k1 và k2 mà không bao gồm bản ghi của k1.
- Nếu true được truyền cho bV2, phương thức trả về tất cả các bản ghi được liên kết với các khóa giữa k1 và k2 bao gồm cả bản ghi của k2.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 |
import java.util.TreeMap; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); System.out.println(sinh_vien.subMap("Nguyen A", false, "Nguyen C", true)); } } |
Kết quả:
1 |
{Nguyen B=22, Nguyen C=27} |
5. Các phương thức khác
Phương thức | Mô tả |
clone() | Tạo một bản sao chép của TreeMap. |
containsKey() | Trả về giá trị kiểu Boolean nếu tồn tại khóa. |
containsValue() | Trả về giá trị kiểu Boolean nếu tồn tại giá trị. |
size() | Trả về kích thước của TreeMap. |
clear() | Xóa tất cả các bản ghi của TreeMap. |
Comparator của TreeMap
Trong tất cả các ví dụ trên, các phần tử của TreeMap được sắp xếp tự nhiên (theo thứ tự tăng dần). Tuy nhiên, chúng ta cũng có thể tùy chỉnh thứ tự các khóa.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import java.util.TreeMap; import java.util.Comparator; class Main { public static void main(String[] args) { TreeMap<String, Integer> sinh_vien = new TreeMap<>(new CustomComparator()); sinh_vien.put("Nguyen A", 23); sinh_vien.put("Nguyen B", 22); sinh_vien.putIfAbsent("Nguyen C", 27); System.out.println(sinh_vien); } public static class CustomComparator implements Comparator<String> { @Override public int compare(String a, String b) { int i = a.compareTo(b); if (i > 0) { return -1; } else if (i < 0) { return 1; } else { return 0; } } } } |
Kết quả:
1 |
{Nguyen C=27, Nguyen B=22, Nguyen A=23} |
Trong ví dụ trên, chúng ta đã tạo một TreeMap truyền vào lớp CustomComparator làm đối số. Lớp CustomComparator triển khai Comparator Interface. Sau đó, chúng ta ghi đè phương thức comapre() để sắp xếp các phần tử theo thứ tự ngược lại.
Trên đây là khái niệm và ví dụ cơ bản về lớp TreeMap trong Java. Hy vọng mọi người có thể áp dụng vào trong chương trình của mình. Mọi người hãy tiếp tục theo dõi các bài tiếp theo và cập nhật các bài mới nhất trên tek4 nhé!
P/s: Cảm ơn mọi người!