【问题标题】:Change "perspective" of multi-dimension tree改变多维树的“视角”
【发布时间】:2015-10-08 17:13:24
【问题描述】:
|-- Car                                |-- Green     
|   |-- Audi                           |   |-- Car        
|   |   |-- Green                      |   |   `-- Audi           
|   |   |-- Blue                       |   `-- Bike             
|   |   `-- Red                        |       `-- BMW  
|   `-- BMW                            |-- Blue     
|       |-- Red                        |   `-- Car         
|       `-- Yellow     ==========>     |       `-- Audi     ==========>     etc.                 
`-- Bike                               |-- Red         
    |-- BMW                            |   |-- Car    
    |   |-- Yellow                     |   |   |-- Audi 
    |   |-- Blue                       |   |   `-- BMW
    |   `-- Green                      |   `-- Bike       
    `-- Honda                          |       `-- Honda       
        |-- Red                        `-- Yellow          
        `-- Yellow                         |-- Car         
                                           |   `-- BMW
                                           `-- Bike
                                               |-- BMW
                                               `-- Honda

我想以通用方式在树构建器中实现几个“透视图”。

这棵树有 6 种可能的排列,我只画了其中的 2 种。

我尝试了什么:

  • 我使用的是通用树结构,其中每个节点都知道它的父节点和子节点,并且都有一个有效负载。
  • 类:TreeBuilderAbstractNodeVehicleNodeColorNodeMakerNode,以及另一个定义级别顺序的枚举有序列表:BY_VEHICLEBY_COLORBY_MAKER - 你可以切换这些以获得所需的视角
  • 遍历枚举列表,将所有特定于该枚举值的实体(汽车、制造商、颜色)收集为对象左右。使用工厂方法,使用 enumValue 创建节点,同时传递树构建器和 parentEnumValue(对于顶级,父枚举值为 NULL)。
  • 子级有一个getParentMember_Internal,它根据parentEnumValue 获取正确的父级(通过使用包含所有数据映射的treeBuilder
  • 在我提到的上一个迭代中,使用结果节点的父对象,我们可以搜索树并查看它是哪个节点(请记住,级别是自上而下创建的,因此父对象已经存在)

为什么它不起作用:

  • 在搜索正确的父级时,树中可能有多个实例,因此我们不得不同时查看祖父级。
  • 此外,分支可能会重复(参见第二棵树)

我在问什么:

  • 这种树/算法是否有特定的命名?我想不出可以在 Google 中使用的英文术语。
  • 它与“K-D 树”有什么关系吗?
  • 有没有通用的方法来做这种事情?

编辑 1 @Andreas

树中只有 3 个可能的实体:VehicleColorMaker。没有“车型”。树中的所有有效载荷都是这三个的子类。

我称它们为“有效负载”,因为每个对象都包装在 AbstractNode 子类(它是树结构的一部分)中,以将数据与表示层分开。示例:VehicleNode has a Vehicle payload

由于实体彼此独立,因此可以隐藏关卡。 这将是一个有效的案例:

|-- Green
|   |-- Audi
|   `-- BMW
|-- Blue
|   `-- Audi
|-- Red
|   |-- Audi
|   |-- BMW
|   `-- Honda
`-- Yellow
    |-- BMW (notice this doesn't appear twice under 'yellow', like in the second tree above)
    `-- Honda

【问题讨论】:

  • 我会尝试使用堆栈并用 preorder、postorder 和 Breathfirst 迭代来提供它?只是快速的想法....嗯,但这也许不能解决您在“为什么它不起作用”中提到的问题
  • 您正在受苦,因为您试图将数据存储在树结构中,而实际上您的数据项之间并没有以这种方式相互关联。我建议您将(车辆、颜色、制造商)三元组彼此不相关地存储,然后从那里构建您的树,而不是尝试将一棵树转换为另一棵树。

标签: java algorithm tree


【解决方案1】:

在 SQL 中,这类似于 Star Schema,在数据仓库数据库中用于 Online Analytical Processing (OLAP)

在您的情况下,这将是一个事实表 Vehicle 和 3 个维度(TypeBrandColor)。

我建议将车辆保存在一个列表中,并从列表中构建 6 个树/索引,而不是尝试将一棵树转换为另一棵树。

一个完全类型化的实现可能是定义一个通用抽象树:

public abstract class Tree<F, D1, D2, D3> {
    protected Tree(List<F> facts) {
        // code here using getDimensionN() to build tree
    }
    protected abstract D1 getDimension1(F fact);
    protected abstract D2 getDimension2(F fact);
    protected abstract D3 getDimension3(F fact);
    public List<F> get(D1 dimension1) {
        // code here
    }
    public List<F> get(D1 dimension1, D2 dimension2) {
        // code here
    }
    public List<F> get(D1 dimension1, D2 dimension2, D3 dimension3) {
        // code here
    }
    // other public accessor methods here
}

然后您可以使用以下代码构建特定的树:

List<F> facts = ...;
Tree<Vehicle, Type, Brand, Color> typeBrandColorTree = new Tree<Vehicle, Type, Brand, Color>(facts) {
    protected Type getDimension1(Vehicle vehicle) { return vehicle.getType(); }
    protected Brand getDimension2(Vehicle vehicle) { return vehicle.getBrand(); }
    protected Color getDimension3(Vehicle vehicle) { return vehicle.getColor(); }
};

// Use of tree
List<Vehicle> audiCars = typeBrandColorTree.get(Type.CAR, Brand.AUDI);

更新

星型模式可能不适合您的特定问题,因此这里有更多关于星型模式的信息。让我用一个例子来说明一个 Fact 可能是什么。

事实可能是车辆的销售,其中跟踪的销售统计数据包括:

  • 类型(汽车、自行车)
  • 品牌(奥迪、宝马、本田)
  • 颜色(绿、蓝、红、黄)
  • 日期
  • 价格

然后可以使用树/索引来回答以下问题:

  • 显示奥迪汽车的销量。
  • 卖出了多少辆 Blue Bikes?
  • 按品牌列出总销售额。

为了更快地访问,树节点甚至可以具有预聚合值,例如 CountTotalPrice,这样您就无需迭代所有事实来获得答案。

这主要用于庞大的数据集(例如10年的全国销售数据),帮助管理者按需快速获取各种汇总统计数据。因此称为“在线分析处理”。

【讨论】:

  • 在您的回答中,VehicleType 对我来说是一回事。我不太了解Fact 表,因为我的数据结构没有“主要”级别(例如车辆)。维度都是相互连接的,没有任何参考点。
  • 如果你让get 返回一个子树而不是一个列表并允许任意参数,那就更棒了。 :)
  • @GGrec 我可能对问题中的“有有效载荷”感到困惑。我假设Vehicle 可以具有比 3 维更多的属性,并且树用于结构化/有序导航和更快地访问子集。
  • @RobAu 有可能,例如将Tree 重命名为Tree3D 并具有Tree2D get(d1)Tree1D get(d1, d2)List get(d1, d2, d3),所有这些都假设同一类型/品牌/颜色组合允许多辆车。
  • @Andreas 编辑了我的问题。你能详细说明一下Fact吗?另外,你能消除每个实体对Vehicle的依赖吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 2016-03-19
相关资源
最近更新 更多