Skip to content

Instantly share code, notes, and snippets.

@dyokomizo
Created September 9, 2011 14:04
Show Gist options
  • Save dyokomizo/1206307 to your computer and use it in GitHub Desktop.
Save dyokomizo/1206307 to your computer and use it in GitHub Desktop.
A comparison of implementations of rotate.
import java.util.List;
public interface Rotator {
<T> void ror(int distance, List<T> list);
<T> void rol(int distance, List<T> list);
}
import static java.util.Collections.reverse;
import java.util.Collections;
import java.util.List;
public class Rotators {
public static Rotator collections() {
return CollectionsRotator.INSTANCE;
}
private static enum CollectionsRotator implements Rotator {
INSTANCE;
@Override public <T> void rol(int distance, List<T> list) {
ror(list.size() - (distance % list.size()), list);
}
@Override public <T> void ror(int distance, List<T> list) {
Collections.rotate(list, distance);
}
@Override public String toString() {
return "java.util.Collections.rotate(List<?>, int)";
}
}
public static Rotator reverseThrice() {
return ReverseRotator.INSTANCE;
}
private static enum ReverseRotator implements Rotator {
INSTANCE;
public <T> void ror(int distance, List<T> list) {
rol(list.size() - (distance % list.size()), list);
}
public <T> void rol(int distance, List<T> list) {
final int l = list.size();
if (l <= 1) { return; }
final int n = modular(distance, l);
if (n == 0) { return; }
reverse(list);
reverse(list.subList(0, l - n));
reverse(list.subList(l - n, l));
}
private int modular(int n, int base) {
if (n < 0) {
return (base + (n % base)) % base;
} else {
return (n % base);
}
}
@Override public String toString() {
return "java.util.Collections.reverse(List<?>) x3";
}
}
private Rotators() {}
}
import static org.junit.Assert.assertEquals;
import java.util.List;
import java.util.Random;
import org.junit.Test;
import com.google.common.base.Charsets;
import com.google.common.primitives.Chars;
public class RotatorTest {
@Test public void performance() {
final int length = 10000;
final long[] jdk = new long[length];
final long[] lib = new long[length];
final String s;
{
final Random r = new Random();
final byte[] bytes = new byte[length];
r.nextBytes(bytes);
s = new String(bytes, Charsets.ISO_8859_1);
}
for (int i = 0; i < s.length(); i++) {
final List<Character> l1 = Chars.asList(s.toCharArray());
final List<Character> l2 = Chars.asList(s.toCharArray());
final Rotator collections = Rotators.collections();
final Rotator reverse = Rotators.reverseThrice();
{
final long before = System.nanoTime();
collections.ror(i, l1);
final long after = System.nanoTime();
jdk[i] = after - before;
}
{
final long before = System.nanoTime();
reverse.ror(i, l2);
final long after = System.nanoTime();
lib[i] = after - before;
}
assertEquals(l1, l2);
}
System.out.println("jdk:" + sum(jdk) + "\r\nlib:" + sum(lib));
}
private long sum(long[] ls) {
long sum = 0;
for (long l : ls) {
sum += l;
}
return sum;
}
}
@dyokomizo
Copy link
Author

The reverse thrice implementation is based on Jon Bentley's Programming Pearls, section 2.3:
http://books.google.com.br/books?id=kse_7qbWbjsC&lpg=PA13&ots=DgsVzSzN3z&hl=en&pg=PA14#v=onepage&q&f=true

Collections.rotate() seems to be 2.5 times faster.

@dyokomizo
Copy link
Author

Hmm, changing everything to be based on arrays, takes off most of the overhead, now the implementation based on reverse is 27% faster than the custom implementation of the jdk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment