There are several ways to select top N objects from A list in the order of multiple data members of an object. For example, you may select top 10 players (top scores) from a list ordered by the players’ score_1, score_2 and then score_3.
The Simplest Way But Ineffective
The simplest way to pick the top N elements is to sort the whole list and get the top N elements. This method is easy to understand and implement but the overhead is too high. It might take a lot of memory or temporary disk resource if the list is big (especially if you need to load all the data from a file or you simple cannot use the normal SQL sorting method to sort the data) and it will takes lot of comparison during sorting. When the list size goes big, the side effect on performance becomes greater too.
The More Effective Way
The more effective way does not necessary always complicated. You can simply use the fixed-size PriorityQueue in java.util package to achieve the same result but with much better performance. PriorityQueue is based on priority heap and the elements in PriorityQueue are ordered according to their natural ordering.
PriorityQueue provides O(log(n)) time for the enqueing and dequeing methods. To make the elements ordered in natural ordering, you need to make sure the element’s class implements the Comparable interface or provide a appropriate Comparator instance for the elements.
Below is an example on how to use PriorityQueue to get Top N objects from a list (either loaded from file or database):
public class TopList {
private T[] tlArray;
private Comparator tlComparator;
private PriorityQueue tlHeapSort;
public TopList(T[] array, Comparator comparator) {
tlArray = array;
tlComparator = comparator;
tlHeapSort = new PriorityQueue(array.length, comparator);
}
public void put(T item) {
if (tlHeapSort.size() < tlArray.length) {
tlHeapSort.add(item);
}
else if (tlComparator.compare(tlHeapSort.peek(), item) < 0) {
tlHeapSort.poll();
tlHeapSort.add(item);
}
}
public void finish() {
int i; // Index
for (i = tlHeapSort.size() - 1; i >=0 ; i--) {
tlArray[i] = tlHeapSort.poll();
}
}
}
public class Player {
int score_1;
int score_2;
int score_3;
String name;
}
public static void main (String args[]) {
Comparator comparator;
Player[] topPlayers;
TopList topList;
Player p;
topPlayers = new Player[10];
comparator = new Comparator() {
@Override
public int compare(Player o1, Player o2) {
int diff1, diff2, diff3;
diff1 = o1.score_1 - o2.score_1;
if (diff1 != 0) return diff1;
diff2 = o1.score_2 - o2.score_2;
if (diff2 != 0) return diff2;
diff3 = o1.score_3 - o2.score_3;
if (diff3 != 0) return diff3;
return 0;
}
}
topList = new TopList(topPlayers, comparator);
// Load from files or database
while (/* has records */) {
p = /* Load a player instance */;
topList.put(p);
}
topList.finish();
// Print the top winners
System.out.printf ("TOP PLAYERS\n");
for (int i = 0; i < topPlayers.length; i++) {
p = topPlayers[i];
if (p == null) break;
System.out.printf ("%d %s (%d, %d, %d)\n",
i + 1, p.name, p.score_1, p.score_2, p.score_3);
}
}
With this implementation, it will not burden your memory and CPU usage, even you have to select only 10 elements out of millions data.
Leave a Reply