package storm.applications.util.math; import java.util.ArrayList; import java.util.List; import backtype.storm.tuple.Tuple; /** * Implementation of BRPRT algorithm: find the kth-smallest element with median-of-median pivoting. * @author yexijiang * */ public class BFPRT { /** * Find the ith-smallest elements in tupleList in O(n). * @param tupleList * @param i * @return */ public static Tuple bfprt(List<Tuple> tupleList, int i) { List<TupleWrapper> tupleWrapperList = new ArrayList<TupleWrapper>(); for (Tuple tuple : tupleList) { tupleWrapperList.add(new TupleWrapper(tuple.getDouble(1), tuple)); } // insertionSort(tupleWrapperList, 0, tupleWrapperList.size()); // return tupleWrapperList.get(i).tuple; Tuple medianTuple = bfprtWrapper(tupleWrapperList, i, 0, tupleWrapperList.size() - 1).tuple; tupleList.clear(); for (TupleWrapper wrapper : tupleWrapperList) { tupleList.add(wrapper.tuple); } return medianTuple; } public static TupleWrapper bfprtWrapper(List<TupleWrapper> tupleWrapperList, int i, int left, int right) { if (left == right) { return tupleWrapperList.get(right); } int p = partitionSingleSide(tupleWrapperList, left, right); if (p == i) { return tupleWrapperList.get(p); } else if (p < i) { // recursively find right part return bfprtWrapper(tupleWrapperList, i, p + 1, right); } else { // (p > i) recursively find left part return bfprtWrapper(tupleWrapperList,i , left, p - 1); } } /** * Partition single side version. * @param tupleWrapperList * @param left * @param right * @return */ public static int partitionSingleSide(List<TupleWrapper> tupleWrapperList, int left, int right) { int pivotIdx = right; TupleWrapper pivot = tupleWrapperList.get(pivotIdx); int bar = left - 1; for(int i = left; i < right; ++i) { if(tupleWrapperList.get(i).compareTo(pivot) < 0) { ++bar; swap(tupleWrapperList, bar, i); } } swap(tupleWrapperList, bar + 1, pivotIdx); return bar + 1; } /** * Sort the group-of-5 with insertionSort. * @param tupleWrapperList * @param left * @param right */ public static void insertionSort(List<TupleWrapper> tupleWrapperList, int left, int right) { for (int i = left + 1; i <= right; ++i) { int iHole = i; TupleWrapper wrapper = tupleWrapperList.get(iHole); while (iHole > 0 && tupleWrapperList.get(iHole - 1).compareTo(wrapper) > 0) { tupleWrapperList.set(iHole, tupleWrapperList.get(iHole - 1)); --iHole; } tupleWrapperList.set(iHole, wrapper); } } private static void swap(List<TupleWrapper> tupleWrapperList, int left, int right) { TupleWrapper tmp = tupleWrapperList.get(left); tupleWrapperList.set(left, tupleWrapperList.get(right)); tupleWrapperList.set(right, tmp); } /** * The wrapper that make the BFPRT algorithm more generic. * @author yexijiang * */ public static class TupleWrapper implements Comparable { double score; Tuple tuple; public TupleWrapper(double score, Tuple tuple) { super(); this.score = score; this.tuple = tuple; } @Override public int compareTo(Object o) { if (o instanceof TupleWrapper) { TupleWrapper wrapper = (TupleWrapper)o; if(score == wrapper.score) { return 0; } else if(score > wrapper.score) { return 1; } else { return -1; } } return 0; } } }