9

I read a previous question about the time complexity for TreeSet and the answer was that it takes O(n) time. However, I don't understand why it is O(n) to iterate instead of O(n*nlogn).

Each next call takes O(logn) time

So if I iterate through a TreeSet like this:

while (iterator.hasNext()){ //Runs N times
   System.out.println(iterator.next() + " "); //each next is O(logn)
}

I would expect for it to be O(n*logn) and not O(n) because the while loop has N iterations and each iterator.next() call takes O(logn) time.

Community
  • 1
  • 1
Eric
  • 2,008
  • 3
  • 18
  • 31

2 Answers2

15

The worst-case time for one next operation is O(log n) because that's the height of the tree. On average, however, the next element can be found in time O(1). This is because the whole traversal in essence uses each of the n-1 tree edges twice.

David Eisenstat
  • 64,237
  • 7
  • 60
  • 120
  • 1
    The code for Iterator.next appears to end up in `TreeMap.Entry.successor()`, here: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/TreeMap.java#TreeMap.successor%28java.util.TreeMap.Entry%29 Yes it seems most of the time the next entry will just be `p.left != null`. However, isn't Big-O supposed to be worst case, not average? – markspace Apr 14 '16 at 21:08
  • 1
    @markspace Big-O describes whatever behavior you want it to since it's not about complexity per se, it's about growth of functions. You can describe average, worst-case, amortized, expected cost, with high probability,...In this case, it's even Theta(n) (worst and best case) for all operations together. Finding a single successor might cost log n time, but iterating all n elements costs at most 2n. – G. Bach Apr 14 '16 at 21:10
  • 1
    @markspace A big-O bound without elaboration refers to the worst-case running time, but big-O notation is just a mathematical statement about a function. – David Eisenstat Apr 14 '16 at 21:11
  • 2
    @markspace Yes, each `iterator.next()` call has worst-case time O(log n). But at the same time, iterating through the whole `TreeSet` has worst-case time O(n). (And in the answer given above, if you're iterating over a whole `TreeSet`, then in the worst case, the average time of `iterator.next()` will be O(1).) – Louis Wasserman Apr 14 '16 at 21:32
0

You can implement the iteration for a tree like this:

void print(Node n) {
   if (n.left != null) print(n.left);
   System.out.println(n.value);
   if (n.right != null) print(n.right);
}

The function print is going to be called exactly once for every node so the total iteration time is O(N). You can implement the exact same algorithm iteratively (without recursion). And if you are careful enough you can have a class to keep the iteration state and advance when .next() is called. It's true that the number of function calls between printlns is uneven but when you look at it overall you will find that there are exactly N of them.

Sorin
  • 11,863
  • 22
  • 26