如何通过Java中的多个标签字段对arraylist进行排序

时间:2012-01-25 09:10:39

标签: java arrays algorithm

Class Activity{
    private int level;
    private Activity predecessor;
}

我的程序会创建Activity的实例,将它们放在Arraylist中,并按两个字段levelpredecessor对它们进行排序。前人首先进行比较。

例如,如果predecessor不是null,则当前活动的前任Activity应该是第一个,它将是第二个。满足predecessor条件后,level可以订购以下内容。

List<Activity> activities = new ArrayList<Activity>();
//Add some activities.
activities.add(Activity);
activities.add(Activity);
Collections.sort(activities,getActivityComparator());

private Comparator<Activity> getActivityComparator() {
    return new Comparator<Activity>() { 
        public int compare(Activity act1, Activity act2) {                
            if (act1 == null) {
                if (act2 == null) {
                    return 0; // Both activities are null
                } else {
                    return -1; // act1 is NULL, so put act1 in the end of
                    // the sorted list
                }
            } else {
                if (act2 == null) {
                    return 1; 
                }
            }

         Activity preAct2 = act2.getPredecessor();
         if(preAct2!=null&&preAct2==act1)
             return -1;

          //Adding this by Joeri Hendrickx's suggestion
         Activity preAct1 = act1.getPredecessor();
         if(preAct1!=null&&preAct1==act2)
             return 1;

         return act2.getLevel()-act1.getLevel(); 
        }
    };
}

我已经编写了上面的代码并进行了大量测试,但是如果我把不同的顺序放到Arrarylist中,它会输出不定的顺序。所以这肯定是不正确的方法来实现这一点。似乎根本原因并不是每两个元素都进行了比较。说活动act1&gt;活动act2(按级别条件),活动act2&gt;活动act3(按级别条件),它不代表活动act1&gt;活动act3(按前身条件)。

在这里,我提出了一个新的想法,即使用冒泡排序而不是使用接口排序集合。它将比较不再需要比较器传递的每两个元素。你觉得怎么样?

任何人都可以帮助我吗?

3 个答案:

答案 0 :(得分:3)

问题是你的比较器没有描述正确的对称和传递关系。

考虑以下三个对象:

act1{predecessor:null, level:1}    
act2{predecessor:act1, level:1}    
act3{predecessor:null, level:0}
act4{predecessor:act2, level:2}

现在,如果comp是比较器,comp(act1, act2)将返回-1,但comp(act2, act1)将返回0.这不是对称

comp(act1, act2)将返回-1,comp(act2, act4)将返回-1,但comp(act1, act4)将返回1.这不是传递

比较器必须描述正确的自反对称传递关系才能使其正常工作。

在看到Axtaxt的帖子后编辑:这里描述的问题无法通过正常排序完成,因为总是可以构建一个场景,通过这些规则,您可以在排序层次结构中获得循环。因此,仅使用此数据来制作传递比较器是不可能的。

答案 1 :(得分:1)

据我了解,由于可能存在以下循环(粗线 - 前驱,细线 - 大于),因此无法使比较器完全传递:

enter image description here

因此,您有一个部分订单,通用排序算法在这里不适用。

如果您只需要在同一活动的后续版本中按级别进行排序,则可以使用以下简单算法来实现:

  • Activity到其直接后继者

  • 构建多图
  • 使用以下属性构建树:

    • 每个节点都包含一个活动,根节点包含null活动
    • 每个节点的子节点对应于其活动的直接后继,按级别排序


    可以使用以下算法创建它:

    • 使用null活动
    • 创建根节点
    • 为每个节点从multimap中提取相应的后继并为它们创建子节点,递归应用

  • 遍历那棵树

答案 2 :(得分:0)

比较器的比较方法定义为: “比较它的两个参数的顺序。当第一个参数小于,等于或大于第二个参数时,返回一个负整数,零或一个正整数。”

这意味着如果你想让act1在其null时结束,你必须返回一个正整数 - &gt; act1更大 - &gt; act1将结束。 你的正面和负面整数是混合的。

if (act1 == null) {
            if (act2 == null) {
                return 0; // Both activities are null
            } else {
                return 1; // act1 is NULL, so put act1 in the end of
                // the sorted list
            }
        } else {
            if (act2 == null) {
                return -1; 
            }
        }

另外,出于同样的原因,您需要使用

return act1.getLevel()-act2.getLevel();

为接收2和3的整数成像比较器。 您希望它返回负int,因为第一个参数小于第二个参数。 - &GT; arg1-arg2 = -1 而不是像你那样做arg2-arg1 ......