Trong hướng dẫn này, chúng ta sẽ 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ó với sự trợ giúp của các ví dụ.

Các lớp TreeSet của framework collection trong Java cung cấp các hàm của một cấu trúc dữ liệu tree.

Nó mở rộng NavigableSet interface.

1. Tạo TreeSet

Để tạo một tập hợp tree, java.util.TreeSet trước tiên chúng ta phải nhập gói.

Sau khi chúng ta nhập gói, đây là cách chúng ta có thể tạo một TreeSet trong Java.

TreeSet<Integer> numbers = new TreeSet<>();

Ở đây, chúng ta đã tạo một TreeSe 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 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 hướng dẫn này.

2. Phương thức của TreeSet

Các lớp TreeSet cung cấp phương thức khác nhau mà cho phép chúng ta thực hiện các hoạt động khác nhau trên tree.

3. Chèn các phần tử vào TreeSet

  • add() – chèn phần tử được chỉ định vào tập hợp
  • 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ụ,

import java.util.TreeSet;

class Main {
    public static void main(String[] args) {

        TreeSet<Integer> evenNumbers = new TreeSet<>();

        // Using the add() method
        evenNumbers.add(2);
        evenNumbers.add(4);
        evenNumbers.add(6);
        System.out.println("TreeSet: " + evenNumbers);

        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(1);

        // Using the addAll() method
        numbers.addAll(evenNumbers);
        System.out.println("New TreeSet: " + numbers);
    }
}

Đầu ra

TreeSet: [2, 4, 6]
New TreeSet: [1, 2, 4, 6]

4. Truy cập phần tử TreeSet

Để truy cập các phần tử của một tập cây, chúng ta có thể sử dụng iterator()phương thức. Để sử dụng phương thức này, chúng ta phải nhập gói java.util.Iterator. Ví dụ,

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

import java.util.TreeSet;
import java.util.Iterator;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(2);
        numbers.add(5);
        numbers.add(6);
        System.out.println("TreeSet: " + numbers);

        // Calling iterator() method
        Iterator<Integer> iterate = numbers.iterator();
        System.out.print("TreeSet using Iterator: ");
        // Accessing elements
        while(iterate.hasNext()) {
            System.out.print(iterate.next());
            System.out.print(", ");
        }
    }
}

Đầu ra

TreeSet: [2, 5, 6]
TreeSet using Iterator: 2, 5, 6,

5. Xóa các phần tử

  • remove() – xóa phần tử được chỉ định khỏi tập hợp
  • removeAll() – xóa tất cả các phần tử khỏi tập hợp

Ví dụ,

import java.util.TreeSet;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(2);
        numbers.add(5);
        numbers.add(6);
        System.out.println("TreeSet: " + numbers);

        // Using the remove() method
        boolean value1 = numbers.remove(5);
        System.out.println("Is 5 removed? " + value1);

        // Using the removeAll() method
        boolean value2 = numbers.removeAll(numbers);
        System.out.println("Are all elements removed? " + value2);
    }
}

Đầu ra

TreeSet: [2, 5, 6]
Is 5 removed? true
Are all elements removed? true

6. Phương pháp điều hướng

Vì lớp TreeSet thực thi NavigableSet, nó cung cấp các phương thức khác nhau để điều hướng qua các phần tử của tập cây.

6.1. phương thức first() và last()

  • first() – trả về phần tử đầu tiên của tập hợp
  • last() – trả về phần tử cuối cùng của tập hợp

Ví dụ,

import java.util.TreeSet;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(2);
        numbers.add(5);
        numbers.add(6);
        System.out.println("TreeSet: " + numbers);

        // Using the first() method
        int first = numbers.first();
        System.out.println("First Number: " + first);

        // Using the last() method
        int last = numbers.last();
        System.out.println("Last Number: " + last);
    }
}

Đầu ra

TreeSet: [2, 5, 6]
First Number: 2
Last Number: 6

6.2. Phương thức  ceiling(), floor(), higher() and lower()

  • higher(element)- Trả về phần tử thấp nhất trong số các phần tử lớn hơn giá trị được chỉ định element.
  • lower(element) – Trả về phần tử lớn nhất trong số các phần tử nhỏ hơn giá trị được chỉ định element.
  • ceiling(element) – Trả về phần tử thấp nhất trong số các phần tử lớn hơn giá trị đã chỉ định thành phần. Nếu element được truyền tồn tại trong một tập hợp cây, nó trả về giá trị element được truyền dưới dạng đối số.
  • floor(element) – Trả về phần tử lớn nhất trong số các phần tử nhỏ hơn giá trị được chỉ định element. Nếu element được truyền tồn tại trong một tập hợp cây, nó trả về giá trị element được truyền dưới dạng đối số.

Ví dụ,

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

import java.util.TreeSet;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(2);
        numbers.add(5);
        numbers.add(4);
        numbers.add(6);
        System.out.println("TreeSet: " + numbers);

        // Using higher()
        System.out.println("Using higher: " + numbers.higher(4));

        // Using lower()
        System.out.println("Using lower: " + numbers.lower(4));

        // Using ceiling()
        System.out.println("Using ceiling: " + numbers.ceiling(4));

        // Using floor()
        System.out.println("Using floor: " + numbers.floor(3));

    }
}

Đầu ra

TreeSet: [2, 4, 5, 6]
Using higher: 5
Using lower: 2
Using ceiling: 4
Using floor: 2

6.3. Phương thức thăm dò pollFirst​​() và pollLast​​()

  • pollFirst() – trả về và xóa phần tử đầu tiên khỏi tập hợp
  • pollLast() – trả về và xóa phần tử cuối cùng khỏi tập hợp

Ví dụ,

import java.util.TreeSet;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(2);
        numbers.add(5);
        numbers.add(4);
        numbers.add(6);
        System.out.println("TreeSet: " + numbers);

        // Using pollFirst()
        System.out.println("Removed First Element: " + numbers.pollFirst());

        // Using pollLast()
        System.out.println("Removed Last Element: " + numbers.pollLast());

        System.out.println("New TreeSet: " + numbers);
    }
}

Đầu ra

TreeSet: [2, 4, 5, 6]
Removed First Element: 2
Removed Last Element: 6
New TreeSet: [4, 5]

6.4. Phương thức headSet(), tailSet() và subSet()

headSet (phần tử, booleanValue)

phương thức headSet()  trả về tất cả các yếu tố của một bộ cây trước khi quy định thành phần (được chuyển như một đối số).

tham số booleanValue là tùy chọn. Giá trị mặc định của nó là false.

Nếu true được thông qua dưới dạng booleanValue, 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 phần tử được chỉ định.

Ví dụ,

import java.util.TreeSet;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(2);
        numbers.add(5);
        numbers.add(4);
        numbers.add(6);
        System.out.println("TreeSet: " + numbers);

        // Using headSet() with default boolean value
        System.out.println("Using headSet without boolean value: " + numbers.headSet(5));

        // Using headSet() with specified boolean value
        System.out.println("Using headSet with boolean value: " + numbers.headSet(5, true));
    }
}

Đầu ra

TreeSet: [2, 4, 5, 6]
Using headSet without boolean value: [2, 4]
Using headSet with boolean value: [2, 4, 5]

tailSet (phần tử, booleanValue)

phương thức tailSet() trả về tất cả các yếu tố của một bộ cây sau khi quy định thành phần (được truyền dưới dạng tham số) bao gồm thành phần.

tham số booleanValue là tùy chọn. Giá trị mặc định của nó là true.

Nếu false được thông qua dưới dạng booleanValue, phương thức trả về tất cả các phần tử sau thành phần mà không bao gồm các thành phần.

Ví dụ,

import java.util.TreeSet;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(2);
        numbers.add(5);
        numbers.add(4);
        numbers.add(6);
        System.out.println("TreeSet: " + numbers);

        // Using tailSet() with default boolean value
        System.out.println("Using tailSet without boolean value: " + numbers.tailSet(4));

        // Using tailSet() with specified boolean value
        System.out.println("Using tailSet with boolean value: " + numbers.tailSet(4, false));
    }
}

Đầu ra

TreeSet: [2, 4, 5, 6]
Using tailSet without boolean value: [4, 5, 6]
Using tailSet with boolean value: [5, 6]

subSet (e1, bv1, e2, bv2)

phương thức subSet() trả về tất cả các yếu tố giữa e1 và e2 kể cả e1.

Các bv1 và bv2là các tham số tùy chọn. Giá trị mặc định củabv1là true, và giá trị mặc định củabv2là false.

Nếu false được truyền vào 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 vào là bv2, phương thức trả về tất cả các phần tử giữa e1 và e2, kể cả e1.

Ví dụ,

import java.util.TreeSet;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(2);
        numbers.add(5);
        numbers.add(4);
        numbers.add(6);
        System.out.println("TreeSet: " + numbers);

        // Using subSet() with default boolean value
        System.out.println("Using subSet without boolean value: " + numbers.subSet(4, 6));

        // Using subSet() with specified boolean value
        System.out.println("Using subSet with boolean value: " + numbers.subSet(4, false, 6, true));
    }
}

Đầu ra

TreeSet: [2, 4, 5, 6]
Using subSet without boolean value: [4, 5]
Using subSet with boolean value: [5, 6]

7. Hoạt động của Set

Các phương thức của lớp TreeSet cũng có thể được sử dụng để thực hiện các hoạt động tập hợp khác nhau.

7.1 Liên hiệp các Set

Để 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ụ,

import java.util.TreeSet;;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> evenNumbers = new TreeSet<>();
        evenNumbers.add(2);
        evenNumbers.add(4);
        System.out.println("TreeSet1: " + evenNumbers);

        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        System.out.println("TreeSet2: " + numbers);

        // Union of two sets
        numbers.addAll(evenNumbers);
        System.out.println("Union is: " + numbers);

    }
}

Đầu ra

TreeSet1: [2, 4]
TreeSet2: [1, 2, 3]
Union is: [1, 2, 3, 4]

7.2 Giao điểm của Set

Để thực hiện giao giữa hai tập hợp, ta sử dụng phương thức retainAll(). Ví dụ,

import java.util.TreeSet;;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> evenNumbers = new TreeSet<>();
        evenNumbers.add(2);
        evenNumbers.add(4);
        System.out.println("TreeSet1: " + evenNumbers);

        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        System.out.println("TreeSet2: " + numbers);

        // Intersection of two sets
        numbers.retainAll(evenNumbers);
        System.out.println("Intersection is: " + numbers);
    }
}

Đầu ra

TreeSet1: [2, 4]
TreeSet2: [1, 2, 3]
Intersection is: [2]

7.3 Sự khác biệt của các set

Để 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ụ,

import java.util.TreeSet;;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> evenNumbers = new TreeSet<>();
        evenNumbers.add(2);
        evenNumbers.add(4);
        System.out.println("TreeSet1: " + evenNumbers);

        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        System.out.println("TreeSet2: " + numbers);

        // Difference between two sets
        numbers.removeAll(evenNumbers);
        System.out.println("Difference is: " + numbers);
    }
}

Đầu ra

TreeSet1: [2, 4]
TreeSet2: [1, 2, 3, 4]
Difference is: [1, 3]

7.4 Tập hợp con của một Tập hợp

Để kiểm tra 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ụ,

import java.util.TreeSet;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        System.out.println("TreeSet1: " + numbers);

        TreeSet<Integer> primeNumbers = new TreeSet<>();
        primeNumbers.add(2);
        primeNumbers.add(3);
        System.out.println("TreeSet2: " + primeNumbers);

        // Check if primeNumbers is subset of numbers
        boolean result = numbers.containsAll(primeNumbers);
        System.out.println("Is TreeSet2 subset of TreeSet1? " + result);
    }
}

Đầu ra

TreeSet1: [1, 2, 3, 4]
TreeSet2: [2, 3]
Is TreeSet2 subset of TreeSet1? True

8. Các phương thức khác của TreeSet

phương thứcSự miêu tả
clone()Tạo một bản sao của TreeSet
contains()Tìm kiếm TreeSet cho phần tử được chỉ định và trả về kết quả boolean
isEmpty()Kiểm tra xem TreeSet có trống không
size()Trả về kích thước của TreeSet
clear()Loại bỏ tất cả các phần tử khỏi TreeSet

Để tìm hiểu thêm, hãy truy cập Java TreeSet (tài liệu Java chính thức) .

9. TreeSet Vs. HashSet

Cả hai TreeSet cũng như HashSet đều triển khai từ Set interface. Tuy nhiên, tồn tại một số khác biệt giữa chúng.

  • Không giống như HashSet, các phần tử trong TreeSet được lưu trữ theo một số thứ tự. Đó là bởi vì TreeSet thực hiện SortedSeti nterface là tốt.
  • TreeSet cung cấp một số phương thức để điều hướng dễ dàng. Ví dụ, first(), last(), headSet(), tailSet()vv Đó là bởi vì TreeSet cũng thực hiện các NavigableSet interface.
  • HashSet nhanh hơn so TreeSet với các thao tác cơ bản như thêm, bớt, chứa và kích thước.

10. Set so sánh TreeSet

Trong tất cả các ví dụ trên, các phần tử của tập hợp cây đượ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ử.

Đối với điều này, chúng ta cần tạo lớp so sánh của riêng mình dựa trên các phần tử trong tập hợp cây được sắp xếp. Ví dụ,

import java.util.TreeSet;
import java.util.Comparator;

class Main {
    public static void main(String[] args) {

        // Creating a tree set with customized comparator
        TreeSet<String> animals = new TreeSet<>(new CustomComparator());

        animals.add("Dog");
        animals.add("Zebra");
        animals.add("Cat");
        animals.add("Horse");
        System.out.println("TreeSet: " + animals);
    }

    // Creating a comparator class
    public static class CustomComparator implements Comparator<String> {

        @Override
        public int compare(String animal1, String animal2) {
            int value =  animal1.compareTo(animal2);

            // elements are sorted in reverse order
            if (value > 0) {
                return -1;
            }
            else if (value < 0) {
                return 1;
            }
            else {
                return 0;
            }
        }
    }
}

Đầu ra

TreeSet: [Zebra, Horse, Dog, Cat]

Trong ví dụ trên, chúng ta đã tạo một tập hợp cây truyền lớp  CustomComparator như một đối số.

lớp CustomComparator thực hiện Comparator interface.

Sau đó, chúng ta ghi đè phương thức compare(). Phương thức sẽ sắp xếp các phần tử theo thứ tự ngược lại.

Để tìm hiểu thêm, hãy truy cập Trình so sánh Java (tài liệu Java chính thức) .

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Nguồn và Tài liệu tiếng anh tham khảo:

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!