试想下这个么个场景:用户可以自己配置多个公式,公式与公式之间又有依赖关系。比如A=B+C ,B=C+D。需要做个算法来排序这些公式。实际我们可以分为两个步骤来看这个问题。
1,配置的公式之间不能死循环依赖。比如A=B+C ,B=A+C。这种A依赖于B,那就的先算B。但是B又依赖于A,的先算A。这就成了死循环,这种必须检测出来,提示用户配置错误。
2,依赖的公式之间必须要排序,这样才能保证计算结果正确。比如:A=B+C ,B=C+D。那么公式排序下来B=C+D就要先算,A=B+C就的后算。
我们定义公式为:
class Formula{
//公式左边属性
private key;
//公式右边属性列表
private Set<String> attributes;
//公式深度
private int depth;
}
我们先看死锁检测:
public void check(List<Formula> formulas){
LinkedList<Formula> formulaLists = new LinkedList<>(formulas);
Formula formula;
while(Objects.nonNull(formula = formulaLists.poll())){
TreeSet<String> feeSets = new TreeSet<>();
relyOn(formula,feeSets,formulas);
}
}
public void relyOn(Formula formula,Set<String> formulaKeyList,List<Formula> formulas){
//将自己加进去
formulaKeyList.add(formula.getKey());
//遍历属性
for(String attr:formula.getAttributeList()){
if(formulaKeyList.contains(attr)){
//在公式列表属性里又找到了自己
}
//继续找到依赖的公式列表(从formulas里找)
List<Formula> feeRelationList = null;
//遍历feeRelationList将formual、sets、formulas再次调用dependsOn
//注意sets需要新定义并将formulaKeyList放进去
}
}
死锁完了再看依赖排序:
public List<Formula> pinfoSort(List<Formula> formulas) {
LinkedList<Formula> formulaLinkedList = new LinkedList<>(formulas);
//定义公式列表A
Formula formula;
while (Objects.nonNull(formula = formulaLinkedList.poll())) {
int depth = getDepth(formula.getAttributes(), formulas);
formula.setDepth(depth);
//往公式列表A加入公式formula
}
//再按深度排序
return 公式列表A;
}
public int getDepth(Set<String> attributeList, List<Formula> formulas) {
int depth = 0;
if (Objects.isNull(attributeList) || attributeList.size() == 0) {
return depth;
}
int max = 0;
for (String attr : attributeList) {
List<Formula> feeRelationList = 继续查找公式依赖列表
for (Formula formula : feeRelationList) {
depth = getDepth(formula.getAttributeList(), formulas);
max = Math.max(depth, max);
}
}
return max + 1;
}