java实现fp-growth算法

2020-12-13 04:00

阅读:412

标签:eva   +=   提升   lsp   lang   步骤   algorithm   代码   near   

最近公司项目上用到频繁项发现算法,于是就用java实现了一个fp-growth算法实现。

环境说明 版本说明 备注
操作系统 debian 9 无 
jdk openjdk 1.8 无 

关于fp-growth算法的原理请参考:

https://www.cnblogs.com/pinard/p/6307064.html 和《机器学习实战》。

FpTreeNode类

package com.slyk.sdp.algorithms.externalAlgorithms.fpTree;

import java.util.ArrayList;
import java.util.List;

/**
 * 描述:fpTree树节点
 * 
 * @param 
 *
 * @author xiaomingyang
 * @created on 2019年5月23日,下午8:01:46
 */
public class FpTreeNode {
    /**
     * 当前节点频繁度
     */
    private long count = 0;
    
    /**
     * 节点内容值
     */
    private T nodeVal;
    
    /**
     * 父类节点
     */
    private FpTreeNode parent = null;
    
    /**
     * 当前节点子节点
     */
    private List> children = null;
    
    /**
     * helper
     */
    private FpTreeHelper helper = null;
    
    public FpTreeNode(long count, T nodeVal, FpTreeNode parent, List> children,
            FpTreeHelper helper) {
        super();
        this.count = count;
        this.nodeVal = nodeVal;
        this.parent = parent;
        this.children = children;
        this.helper = helper;
    }

    /**
     * 描述:添加子节点
     *
     * @param child
     * @return 被添加的子节点
     * @author xiaomingyang
     * @created on 2019年5月23日,下午7:33:13
     */
    public FpTreeNode addChild(FpTreeNode child) {
        if (this.getChildren() == null) {
            children = new ArrayList>();
        }
        child.setParent(this);
        this.children.add(child);
        return child;
    }
    
    /**
     * 描述:向当前节点添加路径
     * 
* List结构数据前一项为后一项数据父节点,例:
* a,b,c,d * * * * * * *
节点 父节点
a null
b a
c b
d c
* *
@param path 树的一条路径,是某个事物下的数据记录列表 * @param parentNode 路径第一个节点的父节点 * @return * @author xiaomingyang * @created on 2019年5月25日,下午9:42:41 */ public void addPath(List path, FpTreeNode parentNode) { if (path == null || path.size() == 0) { return ; } T firstEl = path.get(0); if (parentNode != null && helper.nodeCompare(firstEl, parentNode.getNodeVal())) { parentNode.increaseCountOne(); parentNode.addPath(path.subList(1, path.size()), parentNode); } else { FpTreeNode fnode = new FpTreeNode(1, firstEl, null, null, this.getHelper()); FpTreeNode exsistChild = this.findChild(fnode.getNodeVal()); if (exsistChild != null) { exsistChild.increaseCountOne(); exsistChild.addPath(path.subList(1, path.size()), exsistChild); } else { FpTreeNode node = this.addChild(fnode); node.addPath(path.subList(1, path.size()), node); } } } /** * 描述:计数器加一 * * @return 当前节点计数器 * @author xiaomingyang * @created on 2019年5月23日,下午7:36:21 */ public long increaseCountOne() { return this.increaseCount(1); } /** * 描述: * * @param increasement * @return 当前节点计数器 * @author xiaomingyang * @created on 2019年5月23日,下午7:37:16 */ public long increaseCount(long increasement) { this.count += increasement; return this.count; } /** * 描述: 当前节点寻找指定子节点,有,则返回节点,无则返回null * * @param childVal * @return * @author xiaomingyang * @created on 2019年5月23日,下午7:41:42 */ public FpTreeNode findChild(T childVal) { if (children == null) { return null; } for (FpTreeNode child : children) { if (helper.nodeCompare(child.getNodeVal(), childVal)) { return child; } } return null; } @Override public String toString() { return super.toString() + "-node (val:" + this.getNodeVal() + ", count: " + this.getCount() + ")"; } public long getCount() { return count; } public void setCount(long count) { this.count = count; } public T getNodeVal() { return nodeVal; } public void setNodeVal(T nodeVal) { this.nodeVal = nodeVal; } public FpTreeNode getParent() { return parent; } public void setParent(FpTreeNode parent) { this.parent = parent; } public List> getChildren() { return children; } public void setChildren(List> children) { this.children = children; } public FpTreeHelper getHelper() { return helper; } public void setHelper(FpTreeHelper helper) { this.helper = helper; } }

FpTreeHeader类

package com.slyk.sdp.algorithms.externalAlgorithms.fpTree;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.slyk.sdp.algorithms.externalAlgorithms.fpTree.util.ListSortUtils;

/**
 * 描述:fptree项头表
 * 
 * @param 
 *
 * @author xiaomingyang
 * @created on 2019年5月23日,下午8:05:14
 */
@SuppressWarnings("hiding")
public class FpTreeHeaderextends LinkedHashMap  {
    private static Logger logger = LoggerFactory.getLogger(FpTreeHeader.class);
    
    private static final long serialVersionUID = 1L;
    
    /**
     * 过滤、排序后的原始数据,用以做构建fptree输入数据
     */
    private List> inputData = new LinkedList>();
    
    /**
     * helper
     */
    private FpTreeHelper helper;
    
    /**
     * 节点链,fptree构建后依据项头表建立的节点链列表
     */
    private Map>> treeNodeMap = new LinkedHashMap>>();
    
    /**
     * 描述:添加helper
     *
     * @param helper
     * @return
     * @author xiaomingyang
     * @created on 2019年5月29日,上午10:54:18
     */
    public FpTreeHeader addHelper( FpTreeHelper helper) {
        this.setHelper(helper);
        return this;
    }
    
    /**
     * 描述: 构建节点链列表
     *
     * @param node
     * @author xiaomingyang
     * Created On 2019年5月29日, 上午1:13:27
     */
    protected void buildNodeEntryList(FpTreeNode node) {
        if (node.getCount() != -1) {
            List> nodeList = treeNodeMap.get(node.getNodeVal());
            if (nodeList == null) {
                nodeList = new ArrayList>();
                nodeList.add(node);
                treeNodeMap.put(node.getNodeVal(), nodeList);
            } else {
                nodeList.add(node);
            }
        }
        
        if (node.getChildren() == null) {
            return ;
        }
        
        for (FpTreeNode child : node.getChildren()) {
            buildNodeEntryList(child);
        }
    }
    
    /**
     * 描述:构建项头表
     *
     * @param sourceData
     * @param absSupport
     * @return
     * @author xiaomingyang
     * @created on 2019年5月23日,下午8:36:58
     */
    @SuppressWarnings("unchecked")
    public FpTreeHeader buildTable(List> sourceData, int absSupport) {
        Assert.notNull(this.helper, "helper cannot be null, Set helper first!");
        
        logger.debug("构建项头表.");
        for (List data : sourceData) {
            for (K k : data) {
                if (this.get(k) == null) {
                    this.put(k, 1);
                } else {
                    this.put(k, this.get(k) + 1);
                }
            }
        }
        
        // 过滤不满足项目
        Set> set = this.entrySet();
        Iterator> ite = set.iterator();
        while (ite.hasNext()) {
            java.util.Map.Entry entry = ite.next();
            if (entry.getValue()  absSupport) {
                ite.remove();
            }
        }
        
        // 项头表排序
        List keylist = new ArrayList(this.keySet());
        Map thisRef = (Map) new LinkedHashMap();
        ListSortUtils.sort(keylist, this.getHelper().nodeEleCompare((FpTreeHeader) this));
        for (K k : keylist) {
            thisRef.put(k, (Integer) this.get(k));
        }
        this.clear();
        this.putAll((Map extends K, ? extends java.lang.Integer>) thisRef);
        
        // 对原始输入数据过滤并排序
        for (List data : sourceData) {
            for (Iterator itr = data.iterator(); itr.hasNext(); ) {
                K k = itr.next();
                if (!this.containsKey(k)) {
                    itr.remove();
                }
            }
            FpTreeHeader _this = (FpTreeHeader) this;
            ListSortUtils.sort(data, new Comparator() {
                @Override
                public int compare(K o1, K o2) {
                    int i = _this.get(o2) - _this.get(o1);
                    if (i == 0) {
                        Iterator> itr = _this.entrySet().iterator();
                        int index1 = 0;
                        int index2 = 0;
                        for (int a = 0,b = 0; itr.hasNext(); ) {
                            a = a + 1;
                            b = b + 1;
                            java.util.Map.Entry entry = itr.next();
                            if (helper.nodeCompare(entry.getKey(), o1)) {
                                index1 = a;
                            } else if (helper.nodeCompare(entry.getKey(), o2)) {
                                index2 = b;
                            }
                        }
                        i = index1 - index2;
                    }
                    return i;
                }
                
            });
            if (!data.isEmpty()) {
                inputData.add(data);
            }
        }
        sourceData = null;
        logger.debug("构建项头表完成.");
        return this;
    }

    public List> getInputData() {
        return inputData;
    }

    public void setInputData(List> inputData) {
        this.inputData = inputData;
    }

    public FpTreeHelper getHelper() {
        return helper;
    }

    public void setHelper(FpTreeHelper helper) {
        this.helper = helper;
    }

    public Map>> getTreeNodeMap() {
        return treeNodeMap;
    }

    public void setTreeNodeMap(Map>> treeNodeMap) {
        this.treeNodeMap = treeNodeMap;
    }
}

FpTree类:

package com.slyk.sdp.algorithms.externalAlgorithms.fpTree;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.slyk.sdp.algorithms.externalAlgorithms.fpTree.util.DoubleKeyMap;

/**
 * FPtree
 * 
 * 描述:@param 
 *
 * @author xiaomingyang
 * @created on 2019年6月3日,下午1:34:22
 */
public class FpTree {
    private static Logger logger = LoggerFactory.getLogger(FpTree.class);
    
    /**
     * 项头表
     */
    private FpTreeHeader fpTreeHeader;
    
    /**
     * helper
     */
    private FpTreeHelper helper;
    
    /**
     * root node
     */
    private FpTreeNode root;
    
    /**
     * 默认频繁度阈值
     */
    protected static final int DEFAULT_ABS_SUPPORT = 0xf;
    
    private int absSupport = DEFAULT_ABS_SUPPORT;
    
    /**
     * 默认置信度
     */
    private static final int DEFAULT_CONFIDENT = 3;
    
    /**
     * 置信度
     */
    private int confident = DEFAULT_CONFIDENT;
    
    /**
     * 描述:挖掘树
     * 
代码参考自《机器学习实战》 * *
@param outList * @param tree * @param basePat * @return * @throws ClassNotFoundException * @throws IOException * @author xiaomingyang * @created on 2019年5月31日,下午5:50:45 */ public List> fpGrowth(List> outList, FpTree tree, List prefix) throws ClassNotFoundException, IOException { logger.debug("开始conditionFpTree数据挖掘计算."); // // 挖掘频繁项集的步骤如下: // 1 从FP树提取条件模式基 // 2 用条件模式基构造FP树 // 3 重复1和2直到树只包含一个元素 // DoubleKeyMap, Integer> cpbs = tree.buildPrefixPath(); // 从项头表逆序访问 ListIterator> li = new ArrayList>( this.fpTreeHeader.entrySet()).listIterator(this.fpTreeHeader.size()); for ( ;li.hasPrevious(); ) { Map.Entry entry = li.previous(); T fpHeaderItem = entry.getKey(); List newBasePat = new ArrayList(prefix); newBasePat.add(fpHeaderItem); this.getHelper().resultHandler(newBasePat, confident, entry.getValue()); logger.debug("发现频繁项集:" + newBasePat.toString()); Set> set = cpbs.get(fpHeaderItem).keySet(); Iterator> setItr = set.iterator(); Map> cpbInputData = new LinkedHashMap>(); for ( ; setItr.hasNext(); ) { List cpb = setItr.next(); Integer count = cpbs.get(fpHeaderItem, cpb); for (int repeat = 0; repeat ) { if (!cpb.isEmpty()) { cpbInputData.put(cpb.toString() + "-" + repeat, cpb); } } } FpTree cpbTree = new FpTree(); cpbTree.setHelper(this.getHelper()); cpbTree = cpbTree.init(this.getAbsSupport(), this.getConfident(), cpbInputData); if (!cpbTree.getFpTreeHeader().keySet().isEmpty()) { cpbTree.fpGrowth(outList, cpbTree, newBasePat); } cpbTree = null; cpbInputData = null; } logger.debug("完成conditionFpTree数据挖掘计算."); return outList; } /** * 描述:初始、构建fptree,为数据挖掘做准备 *
* * 输入sourceMap数据结构: * KEY   LIST * T0   1,2,3,4 * T1   1 * T2   3,4 * T3   2,3 * * *
@param absSupport * @param sourceMap * @return * @author xiaomingyang * @created on 2019年5月29日,上午11:53:11 */ public FpTree init(Integer absSupport, Integer confident, Map> sourceMap) { logger.debug("开始fptree构建."); this.absSupport = absSupport == null ? this.getAbsSupport() : absSupport; this.confident = confident == null ? this.getConfident() : confident; List> sourceData = new ArrayList>(); Set keys = sourceMap.keySet(); for (String key : keys) { List inList = sourceMap.get(key); sourceData.add(inList); } this.fpTreeHeader = new FpTreeHeader().addHelper(helper) .buildTable(sourceData, absSupport); sourceData = null; root = buildTree(); // logger.info("构建构建节点链."); this.fpTreeHeader.buildNodeEntryList(root); // logger.info("构建构建节点链完成."); logger.debug("完成fptree构建.."); return this; } /** * 描述:构建条件模式基 * * @return * @author xiaomingyang * @created on 2019年5月29日,下午2:37:47 */ public DoubleKeyMap, Integer> buildPrefixPath() { Assert.notNull(this.fpTreeHeader, "fpTreeHeader cannot be null, Set helper first!"); logger.debug("构建条件模式基"); DoubleKeyMap, Integer> cpb = new DoubleKeyMap, Integer>(); // 从项头表逆序寻找条件模式集 ListIterator> li = new ArrayList>( this.fpTreeHeader.entrySet()).listIterator(this.fpTreeHeader.size()); for ( ;li.hasPrevious(); ) { Map.Entry entry = li.previous(); T fpHeaderItem = entry.getKey(); List> nodeList = this.getFpTreeHeader().getTreeNodeMap().get(fpHeaderItem); for (FpTreeNode node : nodeList) { cpb = findPrefixPath(node, cpb); } } logger.debug("完成构建条件模式基"); return cpb; } /** * 描述:寻找条件模式基 * * @param node 节点链中的节点 * @return * @author xiaomingyang * @created on 2019年5月27日,上午1:05:45 */ private DoubleKeyMap, Integer> findPrefixPath(FpTreeNode node, DoubleKeyMap, Integer> cpb) { Assert.notNull(this.fpTreeHeader, "fpTreeHeader cannot be null, Set helper first!"); List prefixPath = new ArrayList(); FpTreeNode up = node.getParent(); while (up.getParent() != null) { prefixPath.add(up.getNodeVal()); up = up.getParent(); } Collections.reverse(prefixPath); cpb.put(node.getNodeVal(), prefixPath, (int) node.getCount()); return cpb; } /** * 描述:构建fptree * * @return * @author xiaomingyang * @created on 2019年5月24日,上午11:45:34 */ private FpTreeNode buildTree() { Assert.notNull(this.helper, "helpser cannot be null, Set helper first!"); Assert.notNull(this.fpTreeHeader, "fpTreeHeader cannot be null, Set helper first!"); FpTreeNode rootNode = new FpTreeNode(-1, null, null, null, helper); int index = 0; for (List path : this.fpTreeHeader.getInputData()) { rootNode.addPath(path, rootNode); index += 1; logger.debug("fptree完成进度:" + index + "/" + this.fpTreeHeader.getInputData().size()); } return rootNode; } /** * 描述: 打印树,以便直观观察 * * @param node * @param ins * @author xiaomingyang * Created On 2019年5月29日, 上午12:27:43 */ public void display(FpTreeNode node, int ins) { if (node.getParent() == null) { logger.info("打印树形结构如下:"); } System.out.print(StringUtils.repeat(" ", ins) + node.getNodeVal() + " " + node.getCount() + "\n"); if (node.getChildren() == null) { return ; } ins = ins + 1; for (FpTreeNode subNode : node.getChildren()) { display(subNode, ins); } } /** * 描述:deepCopy * * @param src * @return * @throws IOException * @throws ClassNotFoundException * @author xiaomingyang * @created on 2019年5月30日,下午5:28:26 */ @SuppressWarnings("unchecked") public static List deepCopy(List src) throws IOException, ClassNotFoundException { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(src); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(byteIn); List dest = (List) in.readObject(); return dest; } public FpTreeHeader getFpTreeHeader() { return fpTreeHeader; } public void setFpTreeHeader(FpTreeHeader fpTreeHeader) { this.fpTreeHeader = fpTreeHeader; } public FpTreeHelper getHelper() { return helper; } public void setHelper(FpTreeHelper helper) { this.helper = helper; } public FpTreeNode getRoot() { return root; } public void setRoot(FpTreeNode root) { this.root = root; } public int getAbsSupport() { return absSupport; } public void setAbsSupport(int absSupport) { this.absSupport = absSupport; } public int getConfident() { return confident; } public void setConfident(int confident) { this.confident = confident; } }

FpTreeHelper类

package com.slyk.sdp.algorithms.externalAlgorithms.fpTree;

import java.util.Comparator;
import java.util.List;

/**
 * 描述:fptree helper class
 * 
 * @param 
 *
 * @author xiaomingyang
 * @created on 2019年5月23日,下午7:49:46
 */
public interface FpTreeHelper {
    /**
     * 描述:比较目标节点和源节点是否相等,等返回true,否则false
     *
     * @param target
     * @param source
     * @return
     * @author xiaomingyang
     * @created on 2019年5月23日,下午7:52:35
     */
    boolean nodeCompare(T target, T source);
    
    /**
     * 描述:比较节点内容
     *
     * @return
     * @author xiaomingyang
     * @created on 2019年5月29日,上午10:42:35
     */
    Comparator nodeEleCompare(FpTreeHeader header);
    
    /**
     * 描述: 找到的结果处理
     *
     * @param result 单条记录
     * @param extArgs 附加参数
     * @author xiaomingyang
     * Created On 2019年6月2日, 上午1:36:35
     */
    void resultHandler(List result, Object ...extArgs);
}

DoubleKeyMap类

package com.slyk.sdp.algorithms.externalAlgorithms.fpTree.util;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class DoubleKeyMap {
    Map> data = new LinkedHashMap>();

    public Value put(Key1 k1, Key2 k2, Value v) {
        Map data2 = data.get(k1);
        Value prev = null;
        if ( data2==null ) {
            data2 = new LinkedHashMap();
            data.put(k1, data2);
        }
        else {
            prev = data2.get(k2);
        }
        data2.put(k2, v);
        return prev;
    }

    public Value get(Key1 k1, Key2 k2) {
        Map data2 = data.get(k1);
        if ( data2==null ) return null;
        return data2.get(k2);
    }

    public Map get(Key1 k1) { return data.get(k1); }

    /** Get all values associated with primary key */
    public Collection values(Key1 k1) {
        Map data2 = data.get(k1);
        if ( data2==null ) return null;
        return data2.values();
    }

    /** get all primary keys */
    public Set keySet() {
        return data.keySet();
    }

    /** get all secondary keys associated with a primary key */
    public Set keySet(Key1 k1) {
        Map data2 = data.get(k1);
        if ( data2==null ) return null;
        return data2.keySet();
    }

    public Collection values() {
        Set s = new HashSet();
        for (Map k2 : data.values()) {
            for (Value v : k2.values()) {
                s.add(v);
            }
        }
        return s;
    }
    
    @SuppressWarnings("unchecked")
    public void print() {
        System.out.println("条件模式基集合:");
        Set kset = this.keySet();
        for (Iterator itrKey1 = kset.iterator(); itrKey1.hasNext();) {
            Key1 key1 = itrKey1.next();
            for (Iterator itrKey2 = this.get(key1).keySet().iterator(); itrKey2.hasNext();) {
                Object key2 = itrKey2.next();
                System.out.println(key1 + ":" + key2 + "(" + this.get(key1, (Key2) key2) + ")");
            }
        }
    }
}

ListSortUtils类

package com.slyk.sdp.algorithms.externalAlgorithms.fpTree.util;

import java.util.Comparator;
import java.util.List;
import java.util.ListIterator;

/**
 * 描述: 求集合排序,原本集合collections包有排序功能,但是jdk7后改为 timsort排序实现,此类实现存在问题,例如: int[]
 * sample = new int[]
 * {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 * ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,1,0,-2,0,0,0,0};
 * 如上例子数据在timsort排序将会报错,因此排序算法将参考JDK5的LegacyMergeSort算法封装排序。
 *
 * @author xiaomingyang
 *         2019年6月2日,下午11:35:16
 * @version v0.1
 */
public class ListSortUtils {
    /**
     * 描述:参考Collections.sort()方法
     *
     * @param list
     * @param c
     * @author xiaomingyang
     * @created on 2019年6月3日,下午1:35:04
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void sort(List list, Comparator super T> c) {
        Object[] a = list.toArray();
        sort(a, (Comparator) c);
        ListIterator i = list.listIterator();
        for (int j = 0; j ) {
            i.next();
            i.set(a[j]);
        }
    }

    public static void sort(T[] a, Comparator super T> c) {
        T[] aux = (T[]) a.clone();
        if (c == null)
            mergeSort(aux, a, 0, a.length, 0);
        else
            mergeSort(aux, a, 0, a.length, 0, c);
    }

    private static final int INSERTIONSORT_THRESHOLD = 7;

    private static void swap(Object[] x, int a, int b) {
        Object t = x[a];
        x[a] = x[b];
        x[b] = t;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static void mergeSort(Object[] src, Object[] dest, int low,
            int high, int off) {
        int length = high - low;

        // Insertion sort on smallest arrays
        if (length  INSERTIONSORT_THRESHOLD) {
            for (int i = low; i )
                for (int j = i; j > low
                        && ((Comparable) dest[j - 1]).compareTo(dest[j]) > 0; j--)
                    swap(dest, j, j - 1);
            return;
        }

        // Recursively sort halves of dest into src
        int destLow = low;
        int destHigh = high;
        low += off;
        high += off;
        int mid = (low + high) >> 1;
        mergeSort(dest, src, low, mid, -off);
        mergeSort(dest, src, mid, high, -off);

        // If list is already sorted, just copy from src to dest. This is an
        // optimization that results in faster sorts for nearly ordered lists.
        if (((Comparable) src[mid - 1]).compareTo(src[mid]) ) {
            System.arraycopy(src, low, dest, destLow, length);
            return;
        }

        // Merge sorted halves (now in src) into dest
        for (int i = destLow, p = low, q = mid; i ) {
            if (q >= high || p  mid
                    && ((Comparable) src[p]).compareTo(src[q]) )
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static void mergeSort(Object[] src, Object[] dest, int low,
            int high, int off, Comparator c) {
        int length = high - low;

        // Insertion sort on smallest arrays
        if (length  INSERTIONSORT_THRESHOLD) {
            for (int i = low; i )
                for (int j = i; j > low && c.compare(dest[j - 1], dest[j]) > 0; j--)
                    swap(dest, j, j - 1);
            return;
        }

        // Recursively sort halves of dest into src
        int destLow = low;
        int destHigh = high;
        low += off;
        high += off;
        int mid = (low + high) >> 1;
        mergeSort(dest, src, low, mid, -off, c);
        mergeSort(dest, src, mid, high, -off, c);

        // If list is already sorted, just copy from src to dest. This is an
        // optimization that results in faster sorts for nearly ordered lists.
        if (c.compare(src[mid - 1], src[mid]) ) {
            System.arraycopy(src, low, dest, destLow, length);
            return;
        }

        // Merge sorted halves (now in src) into dest
        for (&lt


评论


亲,登录后才可以留言!