【问题标题】:Sorting objects in a recursive generic data structure在递归通用数据结构中对对象进行排序
【发布时间】:2013-09-10 08:46:28
【问题描述】:

我有一个通用树类,其中每个树节点都保存一些数据。每条数据都有一个字符串类型的属性。我想按此属性按字母顺序对每个树节点的子节点进行排序。

树类:

public class Tree<T>{
    public T data;
    public List<Tree<T>> children = new ArrayList<Tree<T>>();
}

请注意,树的子节点是 Tree 类型!

Tree 类的实际类型参数示例如下:

public class DataItem{
    public String name;
}

我的想法是使用 sort() 方法扩展 Tree 类,并使用如下所示的 Comparator,但我被比较函数卡住了:

public class Tree<T>{
    public T data;
    public List<Tree<T>> children = new ArrayList<Tree<T>>();

    public void sort(){
        Collections.sort(this.children,
            new Comparator<Tree<T>>(){
                @Override
                public int compare(Tree<T> objectA, Tree<T> objectB){
                    //I am stuck here!
                    return 0;
                }
            }
        );
        for(Tree<T> child: this.children){
            child.sort();
        }
    }
}

我有不同的想法来解决这个问题:

  • 使用反射访问对象的属性并进行比较。
  • 在 DataItem 中实现接口 Comparable。
  • 使用新接​​口访问对象的属性以进行比较:

    public interface GetComparisonAttribute {
        public String getComparisonAttribute();
    }
    
    public class DataItem implements GetComparisonAttribute{
        public String name;
    
        @Override
        public String GetComparisonAttribute(){
            return this.name;
        }
    }
    
    //the comparison function inside Tree<T>.sort():
    public int compare(Tree<T> objectA, Tree<T> objectB){
        return objectA.data.getComparisonAttribute()
            .compareToIgnoreCase(objectB.data.getComparisonAttribute());
    }
    

什么是正确或最好的做法?还有其他方法吗?

能够指定排序属性可能很重要。

我认为直接在树上使用 Collections.sort() 会很好,但是在这种递归数据结构中实现它真的让我感到困惑。这样做的一个缺点是我无法指定排序属性。

【问题讨论】:

  • 我只浏览了你的代码,所以我可能遗漏了一些明显的东西,但是你的数据结构在做什么,你不能把你的children 保存在SortedSet 中呢?
  • 我在这里提供的数据结构只是一个最小的例子。它有更多的遍历方法和其他花哨的东西,但它们对问题并不重要。通用数据结构对我来说是一个有趣的话题,所以我希望它能够工作。我不认为 SortedSet 或 TreeSet 可以将数据存储在每个节点中,而只能存储在其叶子中。
  • 将孩子放在 SortedSet 中并不能真正解决问题。为此,Tree 必须实现 Comparable,但比较取决于 Tree 的数据属性。嗯,现在我只是认为将数据结构定义为“Tree extends Comparable”解决了部分问题,但它仍然不允许我动态指定 T 的排序属性。
  • 如果你想在Tree 中允许特定类型的参数,为什么不给类型参数-T extends DataItem 添加边界?在这种情况下,您将能够访问DataItem 的属性。
  • @RohitJain The Tree 必须处理任意类型的对象!

标签: java sorting generics tree


【解决方案1】:

试试这个:

public class Tree<T> {
    public T data;
    public List<Tree<T>> children = new ArrayList<Tree<T>>();
    private Class<T> type;

    public Tree(Class<T> t) {
        type = t;
    }

    public void sort(){
        Collections.sort(this.children,
            new Comparator<Tree<T>>(){
                @Override
                public int compare(Tree<T> objectA, Tree<T> objectB){
                if (type==DataItem.class)
                   {
                    DataItem diA = (DataItem) (objectA.data);
                    DataItem diB = (DataItem) (objectB.data);

                    return diA.name.compareTo(diB.name);
                    }
                  else
                    throw new IllegalArgumentException();

                }
            }
        );
        for(Tree<T> child: this.children){
            child.sort();
        }
    }

}

您应该在创建类 Tree 时传递它的类型 T。然后您可以向下转换到DataItem 并根据您喜欢的文件对列表进行排序。除了DataItem,您当然也可以检查其他类型参数。

【讨论】:

  • 我认为这还不够。如果我想将 Tree 与其他类型一起使用,我将不得不更改 Tree! 的代码
  • 如果您不想使用其他数据类型进行排序,那么这就足够了,当您尝试对它们进行排序时,它会抛出异常。如果你想要排序,你应该在 sort() 方法中对其他数据类型执行相同的过程
  • 我查看了您的解决方案,我喜欢它!它绝对帮助我解决了这个问题!
【解决方案2】:
    public void sort(final Comparator<? super T> dataComparator)
    {
        Collections.sort(this.children,
            new Comparator<Tree<T>>()
            {
                @Override
                public int compare(Tree<T> treeA, Tree<T> treeB)
                {
                    return dataComparator.compare(treeA.getData(), treeB.getData());
                }
            }
        );
        for(Tree<T> child: this.children)
        {
            child.sort(dataComparator);
        }
    }


void test()
{
    Tree<DataItem> tree = new Tree<>();

    tree.sort(new Comparator<DataItem>()
    {
        @Override
        public int compare(DataItem dataA, DataItem dataB)
        {
            return dataA.getName().compareTo(dataB.getName());
        }
    });

}

在java8中,可以简化为

    public void sort(final Comparator<? super T> dataComparator)
    {
        Collections.sort(this.children, 
            Comparator.comparing(Tree::getData, dataComparator));

        for(Tree<T> child: this.children)
        {
            child.sort(dataComparator);
        }
    }


void test()
{
    Tree<DataItem> tree = new Tree<>();

    tree.sort( Comparator.comparing(DataItem::getName) );
}

【讨论】:

  • 我想这就是我一直在寻找的!
猜你喜欢
  • 2015-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-07
  • 2021-06-22
  • 1970-01-01
相关资源
最近更新 更多