Trong bài viết này, chúng ta sẽ cùng tìm hiểu về lớp TreeSet trong Java và các hoạt động và phương thức khác nhau của nó cùng với sự trợ giúp của các ví dụ dẫn chứng.
Lớp TreeSet
Lớp TreeSet trong Java cung cấp chức năng của cấu trúc dữ liệu dạng cây. Nó triển khai cho NavigableSet Interface.
Tạo TreeSet
Để tạo một TreeSet, trước tiên chúng ta phải thêm gói java.util.TreeSet. Và sau đây là cách chúng ta có thể tạo một TreeSet trong Java.
1 |
TreeSet<Integer> a = new TreeSet<>(); |
Ở đây, chúng ta đã tạo một TreeSet mà không có bất kỳ đối số nào. Trong trường hợp này, các phần tử trong TreeSet được sắp xếp theo 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 viết này.
Các phương thức của TreeSet
1. Chèn các phần tử
- Phương thức add(): Chèn phần tử được chỉ định vào tập hợp.
- Phương thức addAll(): Chèn tất cả các phần tử của tập hợp được chỉ định vào tập hợp.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.util.TreeSet; class Main { public static void main(String[] args) { TreeSet<String> sinh_vien = new TreeSet<>(); sinh_vien.add("Sinh vien Y"); sinh_vien.add("Sinh vien Luat"); sinh_vien.add("Sinh vien Duoc"); System.out.println(sinh_vien); TreeSet<String> sinh_vien2 = new TreeSet<>(); sinh_vien2.add("Sinh vien Kinh te"); sinh_vien2.addAll(sinh_vien); System.out.println(sinh_vien2); } } |
Kết quả:
1 2 |
[Sinh vien Duoc, Sinh vien Luat, Sinh vien Y] [Sinh vien Duoc, Sinh vien Kinh te, Sinh vien Luat, Sinh vien Y] |
2. Truy cập các phần tử
Để truy cập các phần tử của một TreeSet, chúng ta có thể sử dụng phương thức iterator(). Để sử dụng phương pháp này, chúng ta cần phải thêm gói java.util.Iterator.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<String> sinh_vien = new TreeSet<>(); sinh_vien.add("Sinh vien Y"); sinh_vien.add("Sinh vien Luat"); sinh_vien.add("Sinh vien Duoc"); System.out.println(sinh_vien); TreeSet<String> sinh_vien2 = new TreeSet<>(); sinh_vien2.add("Sinh vien Kinh te"); sinh_vien2.addAll(sinh_vien); Iterator<String> phan_tu = sinh_vien2.iterator(); while(phan_tu.hasNext()) { System.out.print(phan_tu.next()); System.out.print("\n"); } } } |
Kết quả:
1 2 3 4 5 |
[Sinh vien Duoc, Sinh vien Luat, Sinh vien Y] Sinh vien Duoc Sinh vien Kinh te Sinh vien Luat Sinh vien Y |
3. Xóa các phần tử
- Phương thức remove(): Xóa phần tử được chỉ định khỏi tập hợp.
- Phương thức removeAll(): Xóa tất cả các phần tử khỏi tập hợp.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<String> sinh_vien = new TreeSet<>(); sinh_vien.add("Sinh vien Y"); sinh_vien.add("Sinh vien Luat"); sinh_vien.add("Sinh vien Duoc"); TreeSet<String> sinh_vien2 = new TreeSet<>(); sinh_vien2.add("Sinh vien Kinh te"); sinh_vien2.addAll(sinh_vien); boolean kq = sinh_vien2.remove("Sinh vien Kinh te"); System.out.println(kq); System.out.println(sinh_vien2); boolean kq2 = sinh_vien2.removeAll(sinh_vien2); System.out.println(kq2); System.out.println(sinh_vien2); } } |
Kết quả:
1 2 3 4 |
true [Sinh vien Duoc, Sinh vien Luat, Sinh vien Y] true [] |
Các phương thức điều hướng
Vì lớp TreeSet thực hiện triển khai NavigableSet, 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 TreeSet.
1. Phương thức first() và last()
- Phương thức first(): Trả về phần tử đầu tiên của tập hợp.
- Phương thức last(): Trả về phần tử cuối cùng của tập hợp.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<String> sinh_vien = new TreeSet<>(); sinh_vien.add("Sinh vien Y"); sinh_vien.add("Sinh vien Luat"); sinh_vien.add("Sinh vien Duoc"); TreeSet<String> sinh_vien2 = new TreeSet<>(); sinh_vien2.add("Sinh vien Kinh te"); sinh_vien2.addAll(sinh_vien); String a = sinh_vien2.first(); System.out.println(a); String b = sinh_vien2.last(); System.out.println(b); } } |
Kết quả:
1 2 |
Sinh vien Duoc Sinh vien Y |
2. Các phương thức ceiling(), floor(), higher() và lower()
- Phương thức higher(phần tử): Trả về phần tử thấp nhất trong số các phần tử lớn hơn phần tử được chỉ định.
- Phương thức lower(phần tử): Trả về phần tử lớn nhất trong số các phần tử nhỏ hơn phần tử được chỉ định.
- Phương thức ceiling(phần tử): Trả về phần tử thấp nhất trong số các phần tử lớn hơn phần tử đã chỉ định. Nếu phần tử tồn tại trong một TreeSet, nó sẽ trả về phần tử được truyền dưới dạng đối số.
- Phương thức floor(phần tử): Trả về phần tử lớn nhất trong số các phần tử nhỏ hơn phần tử đã chỉ định. Nếu phần tử được truyền tồn tại trong một TreeSet, nó sẽ trả về phần tử được truyền dưới dạng đối số.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<Integer> so_nguyen = new TreeSet<>(); so_nguyen.add(45); so_nguyen.add(43); so_nguyen.add(22); so_nguyen.add(78); System.out.println(so_nguyen.higher(43)); System.out.println(so_nguyen.lower(45)); System.out.println(so_nguyen.ceiling(78)); System.out.println(so_nguyen.floor(22)); } } |
Kết quả:
1 2 3 4 |
45 43 78 22 |
3. Phương thức pollfirst() và pollLast()
- Phương thức pollFirst(): Trả về và xóa phần tử đầu tiên khỏi tập hợp.
- Phương thức pollLast(): Trả về và xóa phần tử cuối cùng khỏi tập hợp.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<Integer> so_nguyen = new TreeSet<>(); so_nguyen.add(45); so_nguyen.add(43); so_nguyen.add(22); so_nguyen.add(78); System.out.println(so_nguyen.pollFirst()); System.out.println(so_nguyen.pollLast()); System.out.println(so_nguyen); } } |
Kết quả:
1 2 3 |
22 78 [43, 45] |
4. Phương thức headSet (), tailSet () và subSet ()
Phương thức headSet (phần tử, giá trị kiểu boolean)
- Phương thức headSet() trả về tất cả các phần tử của một TreeSet trước phần tử đượ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 cho tham số này, phương thức trả về tất cả các phần tử trước phần tử được chỉ định, bao gồm cả phần tử được chỉ định.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<Integer> so_nguyen = new TreeSet<>(); so_nguyen.add(45); so_nguyen.add(43); so_nguyen.add(22); so_nguyen.add(78); System.out.println(so_nguyen.headSet(30, true)); } } |
Kết quả:
1 |
[22] |
Phương thức tailSet (phần tử, giá trị kiểu boolean)
- Phương thức tailSet() trả về tất cả các phần tử của một TreeSet sau phần tử được chỉ định (được truyền dưới dạng tham số) bao gồm cả phần tử được chỉ định.
- Tham số thứ 2 là tùy chọn. Giá trị mặc định của nó là true. Nếu false được truyền cho tham số này, phương thức trả về tất cả các phần tử sau phần tử được chỉ định mà không bao gồm phần tử đã chỉ định.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<Integer> so_nguyen = new TreeSet<>(); so_nguyen.add(45); so_nguyen.add(43); so_nguyen.add(22); so_nguyen.add(78); System.out.println(so_nguyen.tailSet(30, false)); } } |
Kết quả:
1 |
[43, 45, 78] |
Phương thức subSet(e1, bv1, e2, bv2)
- Phương thức subSet() trả về tất cả các phần tử giữa e1 và e2 kể cả e1.
- bv1 và bv2 là các tham số 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 bv1, phương thức trả về tất cả các phần tử giữa e1 và e2 mà không bao gồm e1.
- Nếu true được truyền cho bv2, phương thức trả về tất cả các phần tử giữa e1 và e2, bao gồm cả e1.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<Integer> so_nguyen = new TreeSet<>(); so_nguyen.add(45); so_nguyen.add(43); so_nguyen.add(22); so_nguyen.add(78); System.out.println(so_nguyen.subSet(30, false, 80, true)); } } |
Kết quả:
1 |
[43, 45, 78] |
Các thao tác với tập hợp
1. Kết hợp các tập hợp
Để thực hiện kết hợp giữa hai tập hợp, chúng ta sử dụng phương thức addAll().
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<String> sinh_vien = new TreeSet<>(); sinh_vien.add("Sinh vien Y"); sinh_vien.add("Sinh vien Luat"); sinh_vien.add("Sinh vien Duoc"); TreeSet<String> sinh_vien2 = new TreeSet<>(); sinh_vien2.add("Sinh vien Kinh te"); sinh_vien2.addAll(sinh_vien); System.out.println(sinh_vien2); } } |
Kết quả:
1 |
[Sinh vien Duoc, Sinh vien Kinh te, Sinh vien Luat, Sinh vien Y] |
2. Tìm tập giao của các tập hợp
Để thực hiện phần giao nhau giữa hai tập hợp, chúng ta sử dụng phương thức retainAll().
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<String> sinh_vien = new TreeSet<>(); sinh_vien.add("Sinh vien Y"); sinh_vien.add("Sinh vien Luat"); sinh_vien.add("Sinh vien Duoc"); TreeSet<String> sinh_vien2 = new TreeSet<>(); sinh_vien2.add("Sinh vien Kinh te"); sinh_vien2.retainAll(sinh_vien); System.out.println(sinh_vien2); } } |
Kết quả:
1 |
[] |
3. Tìm sự khác nhau giữa hai tập hợp
Để tính toán sự khác biệt giữa hai tập hợp, chúng ta có thể sử dụng phương thức removeAll().
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.util.TreeSet; import java.util.Iterator; class Main { public static void main(String[] args) { TreeSet<String> sinh_vien = new TreeSet<>(); sinh_vien.add("Sinh vien Y"); sinh_vien.add("Sinh vien Luat"); sinh_vien.add("Sinh vien Duoc"); TreeSet<String> sinh_vien2 = new TreeSet<>(); sinh_vien2.add("Sinh vien Kinh te"); sinh_vien2.add("Sinh vien Duoc"); sinh_vien2.removeAll(sinh_vien); System.out.println(sinh_vien2); } } |
Kết quả:
1 |
[Sinh vien Kinh te] |
4. Kiểm tra tập con của một tập hợp
Để kiểm tra xem một tập hợp có phải là tập hợp con của tập hợp khác hay không, chúng ta sử dụng phương thức containsAll().
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.util.TreeSet; class Main { public static void main(String[] args) { TreeSet<String> sinh_vien = new TreeSet<>(); sinh_vien.add("Sinh vien Y"); sinh_vien.add("Sinh vien Luat"); sinh_vien.add("Sinh vien Duoc"); TreeSet<String> sinh_vien2 = new TreeSet<>(); sinh_vien2.add("Sinh vien Kinh te"); sinh_vien2.add("Sinh vien Duoc"); sinh_vien2.removeAll(sinh_vien); boolean kq = sinh_vien.containsAll(sinh_vien2); System.out.println(kq); } } |
Kết quả:
1 |
False |
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 TreeSet. |
contains() | Trả về kết quả có kiểu Boolean nếu tồn tại phần tử trong TreeSet. |
isEmpty() | Kiểm tra TreeSet rỗng hay không. |
size() | Trả về kích thước của TreeSet. |
clear() | Xóa tất cả các phần tử khỏi TreeSet. |
So sánh lớp HashSet và lớp TreeSet trong Java
Cả TreeSet cũng như HashSet đều triển khai cho Set Interface. Tuy nhiên, tồn tại một số khác biệt sau:
- Không giống như HashSet, các phần tử trong TreeSet được lưu trữ theo một số thứ tự. Đó là vì TreeSet triển khai cho SortedSet Interface.
- TreeSet cung cấp một số phương pháp để điều hướng dễ dàng. Ví dụ, first(), last(), headSet(), tailSet() bởi TreeSet cũng thực hiện triển khai cho NavigableSet Interface.
- HashSet nhanh hơn TreeSet trong các thao tác cơ bản như thêm, bớt, chứa và kích thước.
Comparator trong TreeSet
Trong tất cả các ví dụ trên, các phần tử của TreeSet được sắp xếp tự nhiên. Tuy nhiên, chúng ta cũng có thể tùy chỉnh thứ tự của các phần tử.
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 28 |
import java.util.TreeSet; import java.util.Comparator; class Main { public static void main(String[] args) { TreeSet<String> sinh_vien = new TreeSet<>(new CustomComparator()); sinh_vien.add("Sinh vien Kinh te"); sinh_vien.add("Sinh vien Y"); sinh_vien.add("Sinh vien Luat"); sinh_vien.add("Sinh vien Duoc"); System.out.println(sinh_vien); } public static class CustomComparator implements Comparator<String> { @Override public int compare(String a, String b) { int gia_tri = a.compareTo(b); if (gia_tri > 0) { return -1; } else if (gia_tri < 0) { return 1; } else { return 0; } } } } |
Kết quả:
1 |
[Sinh vien Y, Sinh vien Luat, Sinh vien Kinh te, Sinh vien Duoc] |
Trong ví dụ trên, chúng ta đã tạo một TreeSet và truyền lớp CustomComparator làm đối số. Lớp CustomComparator triển khai cho Comparator Interface. Sau đó, chúng ta ghi đè phương thức compare(). Phương thức bây giờ sẽ 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 TreeSet 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!