树算法中级别的同类值

时间:2013-11-28 13:22:19

标签: java algorithm treeview swt jface

考虑一个有3个级别的树:L1,L2,L3(但这只是一个特殊情况,为方便起见;每个级别的级别和子级数没有限制。)

每个级别都包含一个键和一个值(例如[string, integer])。

算法:如果直接子项都具有相同的值,则不要在子级别上显示这些值,而是在父级别上显示。 只有叶子可以有值,父母只根据叶子内容表示数据

我的解决方案:我改变了主意。我需要一个通用的解决方案,不包括JFace LabelProvider。我按顺序遍历树,并将值保存在地图中。我宁愿只保留没有 null 值的条目(即级别有东西要显示)。绩效至关重要。

    Case 1           Case 2           Case 3
--------------   --------------   --------------  
L1         | 1   L1         | -   L1         | - 
|-- L2     | -   |-- L2     | 1   |-- L2     | -
|   |-- L3 | -   |   |-- L3 | -   |   |-- L3 | 1
|   +-- L3 | -   |   +-- L3 | -   |   +-- L3 | 2
+-- L2     | -   +-- L2     | 2   +-- L2     | -
    |-- L3 | -       |-- L3 | -       |-- L3 | 1
    +-- L3 | -       +-- L3 | -       +-- L3 | 2

<击> 限制:我一次只能访问一个级别,因为我正在使用内容和标签提供程序来填充树。例如,我有一个名为getColumnText(Object element, int columnsIndex)的回调方法,其中element是L1 / L2 / L3的实例,columnIndex与值列重合。

<击>

我的解决方案:根据element对象的实例,我向上和/或向下查看值是否为自杀。如果他们这样做,我不会在element级别显示文本。代码特定于我的项目,因此我不能发布任何内容,因为它会使问题更难。但如果你坚持不懈,我可以写一个伪代码。

问题:我觉得这不是很优化(在每个getColumnText调用上应用算法)。有没有机会推广这个算法?或者我应该将它移到标签提供者之外并将这些“值”保存在地图中?

2 个答案:

答案 0 :(得分:2)

初始化字典D,我们将用它来存储结果。

假设我们在节点n。按如下方式定义Value(n)

  • 如果n是叶节点,则返回其值
  • 假设n有子女c0, c1, .., c(k-1)
  • 设置firstChildValue = Value(c0)
  • 依次为每个int i = 1, i <= k-1执行以下操作:
    • 如果firstChildValue == Value(ci),则不执行任何操作。
    • 如果firstChildValue != Value(ci):如果firstChildValue非空,请将所有子c1, .., c{i-1}添加到D,其值为firstChildValue。然后将每个孩子ci, .., c{k-1}添加到具有所述值的非Value(ci)D返回 null,因为n有不同价值观的孩子。
  • 返回 firstChildValue,因为所有孩子都有相同的价值。

要执行此操作,请致电Value(root),并在root为非空时将Value(root)添加到字典中。

我认为这是你能做的最好的事情,因为它只评估每个节点一次,并且只将必要的节点添加到字典中。

E:感谢@GGrec帮助我调试这个。在与其他人分享之前,这是一种检查事物的教育。

答案 1 :(得分:1)

我认为你应该首先忽略性能。相反,尽量做到通用。编写两个不同的标签提供程序实现,它们不依赖于您的内部数据结构,但可以与其他ILabelProviderITreeContentProvider实例一起使用:

  1. SummarizingLabelProvider会在树上拉出常用标签,因此如果子树的叶子具有相同的标签,则会为此子树的所有节点返回此标签。

  2. 如果父母已经拥有相同的标签,IgnoreDetailsLabelProvider将忽略子标签。

  3. <强> SummarizingLabelProvider#getText(element)

    递归查看树的子项(使用内容提供程序):如果所有子项具有相同的文本,则返回此文本,否则返回元素的原始文本(使用其他标签提供程序)。需要另一个ILabelProviderITreeContentProvider作为构造函数参数。

    <强> IgnoreDetailsLabelProvider#getText(element)

    如果其他标签提供程序返回元素及其父元素的相同文本,则返回null。需要另一个ILabelProviderITreeContentProvider作为构造函数参数。

    现在您可以链接您的标签提供商:

    ILabelProvider lp1 = // original label provider
    ILabelProvider lp2 = new SummarizingLabelProvider(contentProvider, lp1);
    ILabelProvider lp3 = new IgnoreDetailsLabelProvider(contentProvider, lp2);
    
    treeViewer.setLabelProvider(lp3);
    

    <强>性能

    性能最强的标签提供商是SummarizingLabelProvider。对于每个getText(element),在最坏的情况下,它必须遍历element的子树。您可以使用缓存以前计算的文本的Map来优化它。但在这样做之前,你应该测试初始性能是否太低!

    IgnoreDetailsLabelProvider只会根据SummarizingLabelProvider两次调用基础getText,因此它也会从缓存中获利。