【问题标题】:Algorithm for sorting a "plain-list-tree-structure"排序“普通列表树结构”的算法
【发布时间】:2012-06-08 09:56:44
【问题描述】:

对不起,我没有找到更好的标题:-)

我有一个树形结构,这是我的“节点”类:

public class Categoria implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    private String name;

    @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
    @JoinColumn(name = "parent_id")
    private List<Categoria> children = new LinkedList<Categoria>();

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(
        name = "parent_id",
        insertable=false,
        updatable=false
    )
    private Categoria parent;

    @Transient
    private Integer depth;

    private Integer orderNumber;

... getters, setters, ....
}

不要在意Hibernate/JPA注解,它们没有问题,只要想一个理想的pojo世界就行了。

我做了一个递归方法,它构建了一个“普通”的相邻节点列表。所以,想象一下这棵树:

grandfather

 |_ father

    |_ son1

    |_ son2

 |_ uncle

grandmother

 |_ mother

我们将得到一个像这样的结果列表(数字是“深度”): - 祖父 (1) - 父亲 (2) -儿子1(3) -儿子2(3) - 叔叔 (2) - 祖母 (1) - 母亲 (2)

一切都很好。

现在我想让我的用户编辑节点排序(在相同深度节点之间),我的意思是:如果我想在上面列表中的“son1”之前使用“son2”怎么办?

所以我要添加一个“orderNumber”属性:所有 orderNumbers 最初都是 0。 然后我的用户将son1的orderNumber设置为99,将son2的orderNumber设置为88。

问题是:如何重新排列结果列表以根据 orderNumber 进行排序?

但是等等....我只想对“子列表”进行排序,所以儿子排序绝对与“父亲”和“叔叔”排序无关!

感谢您帮助我们。

编辑:你们都缺少一件事。我没有很好地解释自己。这是一个例子:

  • 祖父(深度:1,订单号:1)
  • 父亲(深度:2,订单号:1)
  • son1(深度:3,订单号:1)
  • son2(深度:3,订单号:2)
  • 叔叔(深度:2,订单号:2)
  • 祖母(深度:1,订单号:2)
  • 母亲(深度:2,订单号:1)

现在我想交换 son1 和 son2,所以结果列表将是:

  • 祖父(深度:1,订单号:1)
  • 父亲(深度:2,订单号:1)
  • son2(深度:3,订单号:1)
  • son1(深度:3,订单号:2)
  • 叔叔(深度:2,订单号:2)
  • 祖母(深度:1,订单号:2)
  • 母亲(深度:2,订单号:1)

我怎样才能为此目的实现 sort / compareTo??

【问题讨论】:

  • 父亲是祖父的儿子?还是您基于某个人?
  • 我有一个不可见的“ROOT”元素,我没有把它放在生成的普通列表中。父亲是祖父的儿子。祖父是祖母的兄弟。
  • 记住:orderNumber 不是“全局”的,我的意思是,三个儿子可以有 1,2,3 作为 orderNumber,两个父亲可以有 1,2.... 我如何在子列表之间进行比较?

标签: java algorithm sorting tree


【解决方案1】:

让Categoria 实现Comparable。创建一个自定义 compareTo 实现,您可以在其中按深度排序,并根据您的附加 OrderNumber 属性决定。这适用于任何可排序的集合。

但是根据您使用该树结构解决的问题,为您的树实现自定义迭代器而不是递归创建“列表快照”可能更合适?

【讨论】:

  • 你能更好地解释一下自己吗?我看不到如何实现 compareTo() 我的意思是......我不希望我的“深度 1”元素都是并排的
  • 我现在看到了问题。我认为没有简单的方法可以通过排序来解决这个问题,因为它需要关于整个列表的知识,而不是像 compareTo() 方法那样只有两个元素。您是否绝对必须使用列表并在创建列表后重新排列列表?创建列表时,可以按子数组的 orderNumber 对子数组进行排序。也许您可以详细说明要求?正如我在回答中所说,您应该考虑将树作为数据结构本身公开,而不是将其复制到普通列表中。
  • 谢谢@Pyranja,你是理解的人!我最终在构建列表时进行了排序(我确实需要一个列表,以在 JSF 中构建一个 ,例如)......如何?我有一个递归函数,它在某个点接受“孩子”:我只是对“孩子”列表进行排序,然后再将它传递给同一个函数。做起来比解释简单:)
【解决方案2】:

您可以使用 Collections.sort() 和适当的比较器显式对子列表进行排序。

如果在创建列表时知道排序,您可以使用带有比较器而不是 LinkedList 的有序集(如 TreeSet)。所以在插入的时候项目会被排序。

【讨论】:

    【解决方案3】:

    我会让你的类实现Comparable,并且在compareTo 方法中我会使用字段depthorderNumber 来计算顺序。完成此操作后,您可以使用 Collectoins.sort() 对列表进行排序。

    示例代码:

    public class Categoria implements Serializable, Comparable<Categoria> {
    
        private static final long serialVersionUID = 1L;
    
        // ... omitting other fields/annotations/getters/setters
    
        private Integer depth;
    
        private Integer orderNumber;
    
        @Override
        public int compareTo(Categoria other) {
            if (depth < other.depth)
                return -1;
            if (depth > other.depth)
                return 1;
            // if we get here the two objects have the same depth, so we compare 
            // based on orderNumber
            if (orderNumber < other.orderNumber)
                return -1;
            if (orderNumber > other.orderNumber)
                return 1;
            return 0;
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      我需要那个:

      private List<Categoria> getAlberoCategorie(Categoria root, int profondita) {
              List<Categoria> tmpList = new ArrayList<Categoria>();
              root.setProfondita(profondita);
              if ( root.getParent() != null ) {
                  Hibernate.initialize(root.getTraduzioni());
                  tmpList.add(root);
              }       
      
              List<Categoria> children = root.getChildren();
              Collections.sort(children, new Comparator<Categoria>() {
                  @Override
                  public int compare(Categoria o1, Categoria o2) {
                      return o1.getOrdinamento().compareTo(o2.getOrdinamento());
                  }
              });
      
              if (!children.isEmpty()) {
                  profondita++;
                  for (Categoria figlia : children) {
                      List<Categoria> discendenza = getAlberoCategorie(figlia,profondita);                
                      tmpList.addAll(discendenza);
                  }
              }       
              return tmpList;
          }
      

      还是谢谢大家!

      【讨论】:

        猜你喜欢
        • 2013-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-24
        • 2017-08-20
        • 2013-01-31
        • 1970-01-01
        • 2022-09-28
        相关资源
        最近更新 更多