Структуры данных в Java — NavigableSet

от автора

В данной статье я хотел бы рассмотреть очень узконаправленный и редко используемый, но достаточно полезный в некоторых случаях, интерфейс NavigableSet.
Интерфейс унаследован от SortedSet и расширяет методы навигации находя ближайшее совпадение по заданному значению. И сродни родительскому интерфейсу в NavigableSet не может быть дубликатов.
Рассмотрим полезность и удобство применения его методов на практике.

Предположим ситуацию, при которой мы имеем некий массив дробных чисел (в моем случае 6 чисел после запятой), в котором нужно производить операции поиска ближайших значений.

double n0 = 0.755544; double n1 = 0.755444; double n2 = 0.755543; double n3 = 0.784554; double n4 = 0.884554; double n5 = 0.484554; 

Как вы можете заметить, даже в таком небольшом массиве данных, где числа отличаются лишь тысячными, при работе вручную увеличивается сложность работы с имеющимися данными, что может привести к ошибке.
Метод
lower() – возвращает наибольший элемент в наборе, но строго меньше чём заданный если такого элемента нет, то в результате будет возвращено null.
floor()– возвращает наибольший элемент в наборе, но меньше чём заданный или равный ему, в случае отсутствия такого элемента будет возвращено null.
ceiling() – возвращает ближайший элемент в наборе, но который больше или равняется заданному, в случае отсутствия такого элемента будет возвращено null.
higher() – возвращает ближайший элемент в наборе, но строго больше чём заданный, в случае отсутствия такого элемента будет возвращено null.
Итак, возьмем наименьшее число (n5 = 0.484554) в сете и посмотрим на поведение этих методов в работе.

Код

Object o = ns.lower(n5);  System.out.println(o);       Object o1 = ns.floor(n5);  System.out.println(o1);       Object o2 = ns.ceiling(n5);  System.out.println(o2);       Object o3 = ns.higher(n5);  System.out.println(o3);      В результате: null 0.484554 0.484554 0.755444  

Как можно заметить что при вызове метода lower() для наименьшего числа компилятор выдал null() по причине отсутствия подходящих значений. Метод floor() вернул искомое значение в связи с отсутствием элементов, меньше чём заданный, но эквивалентное заданному числу. Методы ceiling() и higher() сработали по вышеуказанным описаниям.

Для доступа ко всем элементам набора поочередно в NavigableSet используется встроенный итератор, вывод может быть осуществлен как в порядке возрастания, так и спадания с помощью методов iterator() и descendingIterator(). Например:

Iterator iter = ns.descendingIterator();          while (iter.hasNext()) {             System.out.print(iter.next() + " ");         }  

В результате в консоли получим такой результат:

0.884554; 0.784554; 0.755544; 0.755543; 0.755444; 0.484554

Создадим класс Car с имплементацией интерфейста Comparable, и переопределением метода compareTo, в данном случае сравнивающем по общему пробегу автомобиля для изучения последующих методов.

Код

4    public class Car implements Comparable<Car> {  5        private String carBrand;  6        private double displacemet;  7        private double mileage;  8      9        public Car(String carBrand, double displacemet, double mileage) {  10           this.carBrand = carBrand;  11           this.displacemet = displacemet;  12           this.mileage = mileage;  13       }  14     15       public String getCarBrand() {  16           return carBrand;  17       }  18     19       public void setCarBrand(String carBrand) {  20           this.carBrand = carBrand;  21       }  22     23       public double getDisplacemet() {  24           return displacemet;  25       }  26     27       public void setDisplacemet(double displacemet) {  28           this.displacemet = displacemet;  29       }  30     31       public double getMileage() {  32           return mileage;  33       }  34     35       public void setMileage(double mileage) {  36           this.mileage = mileage;  37       }  38     39       @Override  40       public String toString() {  41           final StringBuilder sb = new StringBuilder("Car{");  42           sb.append("carBrand = '").append(carBrand).append('\'');  43           sb.append(", displacemet = ").append(displacemet);  44           sb.append(", mileage = ").append(mileage);  45           sb.append('}');  46           return sb.toString();  47       }  48     49       @Override  50       public int compareTo(Car o) {  51           if (this.getMileage() < o.getMileage()) return -1;  52           if (this.getMileage() > o.getMileage()) return 1;  53           return 0;  54       }   

В методе main() создадим NavigableSet и наполним его нашими автомобилями:

Код

8      public static void main(String[] args) {  9      10           NavigableSet<Car> navigableSet = new TreeSet<Car>();  11     12           Car car0 = new Car("Opel", 1.8,  52025);  13           Car car1 = new Car("Mersedes", 3.2,  90000);  14           Car car2 = new Car("Lada Kalina", 1.7,  300000);  15           Car car3 = new Car("Mitsubishi Lancer", 1.5,  64021);  16           Car car4 = new Car("Toyota Camry", 2.2,  51000);  17           Car car5 = new Car("Honda Accord", 2.0,  17000);  18     19           navigableSet.add(car0);  20           navigableSet.add(car1);  21           navigableSet.add(car2);  22           navigableSet.add(car3);  23           navigableSet.add(car4);  24           navigableSet.add(car5);  

Метод pollFirst() –получает и удаляет из сета первый наименьший элемент(), или возвращает null в случае если сет пустой. Запустим этот метод и выведем общий набор в консоль.

Код

27           System.out.println(navigableSet.pollFirst());  28     29           System.out.println("-------------------");  30     31           Iterator iterator = navigableSet.iterator();  32           while (iterator.hasNext()){  33               System.out.println(iterator.next());  34           }     Car{carBrand = 'Honda Accord', displacemet = 2.0, mileage = 17000.0} ------------------------------------------------------------------------------------------------ Car{carBrand = 'Toyota Camry', displacemet = 2.2, mileage = 51000.0} Car{carBrand = 'Opel', displacemet = 1.8, mileage = 52025.0} Car{carBrand = 'Mitsubishi Lancer', displacemet = 1.5, mileage = 64021.0} Car{carBrand = 'Mersedes', displacemet = 3.2, mileage = 90000.0} Car{carBrand = 'Lada Kalina', displacemet = 1.7, mileage = 300000.0}  

Как видим, это автомобиль с наименьшим пробегом 17000.0, и как указано в документации к методу, он был удален из общего числа перечисленных транспортных средств.
Метод pollLast() действует абсолютно противоположно предыдущему. И в случае выполнения на экране появится.
Car{carBrand = 'Lada Kalina', displacemet = 1.7, mileage = 300000.0}

Вы также можете вносить изменения в метод compareTo(), или создать отдельный компаратор который будет сравнивать по другому параметру и сортировать согласно внесенным изменениям.

headSet(), возвращает данные которые меньше заданного либо равно. Например:

Код

SortedSet navSet1 = navigableSet.headSet(car3);             for (Object o : navSet1) {                 System.out.println(o);             }   Car{carBrand = 'Honda Accord', displacemet = 2.0, mileage = 17000.0} Car{carBrand = 'Toyota Camry', displacemet = 2.2, mileage = 51000.0} Car{carBrand = 'Opel', displacemet = 1.8, mileage = 52025.0}  

Код

NavigableSet navSet2 = navigableSet.headSet(car3,  true);  //true  указывает на то что указанный элемент должен быть включен            for (Object c : navSet2) {                     System.out.println(c);                                                                           }   Car{carBrand = 'Honda Accord', displacemet = 2.0, mileage = 17000.0} Car{carBrand = 'Toyota Camry', displacemet = 2.2, mileage = 51000.0} Car{carBrand = 'Opel', displacemet = 1.8, mileage = 52025.0} Car{carBrand = 'Mitsubishi Lancer', displacemet = 1.5, mileage = 64021.0}  

Хочу обратить внимание что установленная Car3 выводит меньшие элементы, согласно настройкам метода compareTo(), и это же правило действует в методах описанных ниже.
tailSet() действует по такому же принципу, только возвращает данные больше заданного.
subset() дает вывести вам данные согласно двум заданным границам. Используя SortedSet, будет выведено первое указанное значение и все последующие, но не последнее. С NavigableSet вывод первого и последнего регулируется флагами true or false.

Пример

SortedSet navSet1 = navigableSet.subSet(car5, car3);             for (Object o : navSet1) {                 System.out.println(o);             }   Car{carBrand = 'Honda Accord', displacemet = 2.0, mileage = 17000.0} Car{carBrand = 'Toyota Camry', displacemet = 2.2, mileage = 51000.0} Car{carBrand = 'Opel', displacemet = 1.8, mileage = 52025.0}             NavigableSet navSet2 = navigableSet.subSet(car5, true, car3, true);             for (Object c : navSet2) {                 System.out.println(c);             }   Car{carBrand = 'Honda Accord', displacemet = 2.0, mileage = 17000.0} Car{carBrand = 'Toyota Camry', displacemet = 2.2, mileage = 51000.0} Car{carBrand = 'Opel', displacemet = 1.8, mileage = 52025.0} Car{carBrand = 'Mitsubishi Lancer', displacemet = 1.5, mileage = 64021.0} 

ссылка на оригинал статьи http://habrahabr.ru/post/232963/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *