Is the computational complexity of TreeSet methods in Java, same as that of an AVLTree?
Specifically, I want to know the computational complexity of the following methods: 1.add 2.remove 3.first 4.last 5. floor 6. higher
Java Doc for method description: http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html
For an AVL Tree, there are all O(logn)? Whats the complexity of the above TreeSet Methods?
EDIT: It should be clarified that the time order usually refers to the number of comparisons. Some operations have no comparisons, so the time order could be taken from the number of sub-tasks
The code below prints the following in Java 8
O(1) comparisons, however the number of indirections could be O(ln N)
Performing 10,000 first operations -> 0.0 comparisons/operation
Performing 10,000 last operations -> 0.0 comparisons/operation
Performing 10,000 size operations -> 0.0 comparisons/operation
Performing 10,000 isEmpty operations -> 0.0 comparisons/operation
Performing 10,000 comparator operations -> 0.0 comparisons/operation
Performing 10,000 pollFirst operations -> 0.0 comparisons/operation
Performing 10,000 pollLast operations -> 0.0 comparisons/operation
Performing 10,000 headSet operations -> 1.0 comparisons/operation
O(ln N) comparisons
Performing 10,000 add operations -> 12.9 comparisons/operation
Performing 10,000 ceiling operations -> 12.9 comparisons/operation
Performing 10,000 contains operations -> 12.9 comparisons/operation
Performing 10,000 floor operations -> 12.9 comparisons/operation
Performing 10,000 higher operations -> 13.9 comparisons/operation
Performing 10,000 lower operations -> 13.9 comparisons/operation
Performing 10,000 remove operations -> 10.9 comparisons/operation
O(N ln N) comparisons
Performing 10,000 equals operations -> 128853.0 comparisons/operation
the code
public class TreeSetOrderMain {
public static void main(String[] args) {
System.out.println("O(1) comparisons, however the number of indirections could be O(ln N)");
testOrder("first", (s, i) -> s.first());
testOrder("last", (s, i) -> s.last());
testOrder("size", (s, i) -> s.size());
testOrder("isEmpty", (s, i) -> s.isEmpty());
testOrder("comparator", (s, i) -> s.comparator());
testOrder("pollFirst", (s, i) -> s.pollFirst());
testOrder("pollLast", (s, i) -> s.pollLast());
testOrder("headSet", TreeSet::headSet);
System.out.println("O(ln N) comparisons");
testOrder("add", TreeSet::add);
testOrder("ceiling", TreeSet::ceiling);
testOrder("contains", TreeSet::contains);
testOrder("floor", TreeSet::floor);
testOrder("higher", TreeSet::higher);
testOrder("lower", TreeSet::lower);
testOrder("remove", TreeSet::remove);
System.out.println("O(N ln N) comparisons");
Set<Long> set = LongStream.range(0, 10_000).mapToObj(i -> i).collect(Collectors.toSet());
testOrder("equals", (s, i) -> s.equals(set));
}
static void testOrder(String desc, BiConsumer<TreeSet<Long>, Long> op) {
final LongComparator comparator = new LongComparator();
TreeSet<Long> longs = new TreeSet<>(comparator);
final int count = 10_000;
for (long i = 0; i < count; i++)
longs.add(i);
comparator.count = 0;
for (long i = 0; i < count; i++)
op.accept(longs, i);
System.out.printf("Performing %,d %s operations -> %.1f comparisons/operation%n",
count, desc, (double) comparator.count / count);
}
static class LongComparator implements Comparator<Long> {
long count = 0;
@Override
public int compare(Long o1, Long o2) {
count++;
return Long.compare(o1, o2);
}
}
}
Operations which work on a single element are all O(ln n) comparisons except first and last which are O(1) comparisons or O(ln N) node search time.
comparator(), iterator(), clear(), first(), isEMpty(), size(), last(), pollFirst(), pollLast(), headSet() are O(1)
add(), ceiling(), contains(), floor(), higher(), lower(), remove(), subSet(), tailSet() are O(ln N)
clone(), hashCode(), toArray() and toString() are O(n) for operations, but no comaprisons