/*
Code example for the blog entry
"Java Battle Royal: LinkedList vs ArrayList vs DynamicIntArray"
"silly" linear search then insertion to prove a point.
Java: Linked-list vs ArrayList vs DynamicIntArray. This code was an improved of David's (faulty) example (http://i...content-available-to-author-only...e.com/lmNDj)
i.e. http://k...content-available-to-author-only...s.com/2012/08/08/java-galore-linkedlist-vs-arraylist-vs-dynamicintarray/
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;
import java.util.Vector;
import java.io.IOException;
public class Main {
class DynamicIntArray {
private int[] storage;
private int size;
private final int INITIAL_CAPACITY = 8;
private final int GROW_FACTOR = 2;
private void rangeCheck(int index){
if(index < 0 || index >= size)
}
// ref: http://w...content-available-to-author-only...t.net/Data_structures/Dynamic_array/Capacity_management
private void ensureCapacity(int size_wanted) {
int max_capacity = storage.length;
if (size_wanted > max_capacity) {
max_capacity = max_capacity * GROW_FACTOR +1;
// http://d...content-available-to-author-only...e.com/javase/6/docs/api/java/util/Arrays.html#copyOf%28int[],%20int%29
storage
= Arrays.
copyOf(storage, max_capacity
); // increases array size + copy contents }
}
public DynamicIntArray() {
storage = new int[INITIAL_CAPACITY];
size = 0;
}
public int size() {return size;}
public boolean equals(List<Integer> list)
{
boolean success = (list.size() == size());
if(success) {
for(int idx = 0; success && (idx < size()); ++idx) {
success = success && (get(idx) == list.get(idx).intValue());
}
}
return success;
}
public int get(int position){
rangeCheck(position);
return storage[position];
}
public void set(int index, int value){
rangeCheck(index);
storage[index] = value;
}
public void add(int value) {
insertAt(size, value); // same as c++ std::vector push_back
}
// Insert the value at the given index and shift 'tail' to give space.
// The value can either be last position (size) or within the range 0 -> size.
public void insertAt(int index, int value) {
if(index < 0 || index > size) // allows for push_back to last index also
ensureCapacity(size+1);
int move_count = size - index; // number of elements to shift
if( move_count > 0)
System.
arraycopy(storage, index, storage, index
+1, move_count
);
storage[index] = value;
size++;
}
public void removeAt(int index) {
rangeCheck(index);
int move_count = size - index - 1;
if (move_count > 0)
System.
arraycopy(storage, index
+ 1, storage, index, move_count
);
size--;
}
public void printAll() {
for (int idx = 0; idx < size; idx++)
System.
out.
printf(" [%d]=%d", idx, get
(idx
));
}
} // DynamicIntArray
static class Result {
int size;
long linkedListTime;
long arrayListTime;
long dynamicArrayTime;
public Result(int size) {
this.size = size;
}
}
Main obj = new Main();
// warm up code to make the benchmark more accurate
for (int i = 0; i < 100; i++)
obj.listVsVectorLinearPerformance(1000);
// print the header
System.
out.
printf("%-15s %-20s %-20s %-20s%n",
"#Elements", "LinkedList", "ArrayList", "DynamicArray");
// perform the benchmarking
printResult(obj.listVsVectorLinearPerformance(100));
printResult(obj.listVsVectorLinearPerformance(200));
printResult(obj.listVsVectorLinearPerformance(500));
printResult(obj.listVsVectorLinearPerformance(1000));
printResult(obj.listVsVectorLinearPerformance(2000));
printResult(obj.listVsVectorLinearPerformance(3000));
printResult(obj.listVsVectorLinearPerformance(4000));
printResult(obj.listVsVectorLinearPerformance(5000));
printResult(obj.listVsVectorLinearPerformance(10000));
// printResult(obj.listVsVectorLinearPerformance(20000)); // CPU time exceeded
}
private static void printResult(Result r) {
long min
= Math.
min(r.
linkedListTime,
Math.
min(r.
arrayListTime, r.
dynamicArrayTime));
System.
out.
printf("%-15d %-10d (%-3.0f%%) %-10d (%-3.0f%%) %-10d (%-3.0f%%)%n",
r.size,
r.linkedListTime, (100 * (double) r.linkedListTime) / min,
r.arrayListTime, (100 * (double) r.arrayListTime) / min,
r.dynamicArrayTime, (100 * (double) r.dynamicArrayTime) / min);
}
private Result listVsVectorLinearPerformance(int size) {
LinkedList
<Integer
> linkedList
= new LinkedList
<Integer
>(Arrays.
asList(-1)); ArrayList
<Integer
> arrayList
= new ArrayList
<Integer
>(Arrays.
asList(-1)); DynamicIntArray dynamicArray = new DynamicIntArray();
dynamicArray.add(-1);
for (int i = 0; i < array.length; i++)
array
[i
] = random.
nextInt(Integer.
MAX_VALUE);
Result result = new Result(size);
long before
= System.
nanoTime(); linearInsertion(array, linkedList);
result.
linkedListTime = (System.
nanoTime() - before
) / 1000;
linearInsertion(array, arrayList);
result.
arrayListTime = (System.
nanoTime() - before
) / 1000;
linearInsertionToDynamicArray(array, dynamicArray);
result.
dynamicArrayTime = (System.
nanoTime() - before
) / 1000;
// check that they are equal
if (!(linkedList.equals(arrayList) && dynamicArray.equals(arrayList)))
return result;
}
private static void linearInsertion
(Integer[] intArray, LinkedList
<Integer
> list
) { for (ListIterator<Integer> it = list.listIterator(); it.hasNext();) {
if (integer.compareTo(it.next()) >= 0) {
it.previous(); // should be added before element
it.add(integer);
break;
}
}
}
}
// 1. Avoid calling size() a lot makes actually a big difference
// 2. NEVER use iterators to loop through and ArrayList. Random access is so much faster
// ref: http://d...content-available-to-author-only...e.com/javase/1.4.2/docs/api/java/util/RandomAccess.html
private static void linearInsertion
(Integer[] intArray, ArrayList
<Integer
> list
) { int list_size = list.size(); // on purpose: it is smarter to avoid calling size() every loop
for (int i = 0; i < list_size; i++) {
if (integer.compareTo(list.get(i)) >= 0) {
list.add(i, integer);
break;
}
}
}
}
private static void linearInsertionToDynamicArray
(Integer[] numbers, DynamicIntArray array
) { int value = integer.intValue();
// int array_size = array.size(); // on purpose: even faster would be to avoid calling size() every loop
for(int idx = 0; idx < array.size(); idx++){
if(value >= array.get(idx)){
array.insertAt(idx, value);
break;
}
}
}
}
}