按时间戳排序对象,然后按组依赖关系排序

时间:2017-03-26 03:50:44

标签: arrays algorithm sorting grouping

我们说我有一个对象列表(数组)。这些对象中的每一个都有两个属性:时间戳和可选的父对象,可以为null。我想首先按时间戳排序这个数组,这很容易;但是,我希望依赖对象保持连续。

例如,考虑这个简化示例:三个对象,A,B和C.B'父对象是A,但时间戳是A = 1,B = 3,C = 2。按时间戳排序给出[A,C,B],但是因为B的父母是A,我希望B来自A;所以理想的结果应该是[A,B,C]。

请注意,如果两个或多个对象具有相同的父对象,则它们应该都是相邻的,但它们应该按时间戳相对排序。

最好的方法是什么?我能想到的唯一方法是按时间戳排序,然后遍历数组,对于每个依赖对象,将其移动到其父对象之后;但这似乎效率低下,因为它要求额外的一轮迭代。有没有办法将分组合并到初始排序中,这样它只能完成一轮排序? (我目前正在使用QuickSort,但如果需要,我可以切换到另一种算法。)

2 个答案:

答案 0 :(得分:1)

您可以使用一个或两个数字的序列作为排序键将对象排序为字典顺序,其中如果对象没有父对象,则序列中的单个元素是其编号,如果对象具有父对象序列中的第一个元素是其父元素号,第二个元素是它自己的号码。

所以A,B和C得到序列{1},{1,3},{2}和B在其父级之后排序。

答案 1 :(得分:1)

暴力非工作方法 - 在一个操作中执行排序的一个选项,您需要以下列方式使排序键的父项成为一部分,而不是按{order(Node.Parent),timestamp(Node)}排序使用您喜欢的任何算法进行配对。

  • " A是B"的父母。 => "订单(A)<顺序(B)"和
  • " C.timestamp< D.timestamp" =>订单(C)<顺序(d)

不幸的是这个"命令"函数需要首先对所有子节点进行排序以满足第二个条件,从而打破"一种类型"要求。

要获得单一排序,您可以使用包含所有父节点的时间戳的组合键,然后按此组合键排序。

构建组合键的最简单方法是使用父对象构造树,并使用任何tree traversal将键的值设置为父级键和自己的时间戳的连接。

样品:

  • 数据

    A (ts = 5) parent of B (ts = 7),C (ts = 2)
    B parent of D (ts = 3)
    
  • 构建树:

    A -> B -> D  
      -> C
    
  • 预订遍历:A,B,D,C

  • 复合键 -

    A - > A.timestamp = 5    B - > key(A)concat B.timestamp = 5.7    C - > key(A)concat C.timestamp = 5.2    D - > key(B)concat D.timestamp = 5.7.2

  • 按{order,timestamp}对

    排序的数据
     A {order(no-parent), ts} = {0, 5}
     B {order(A), ts} = {1,7}
     C {1,2}
     D {2,3}
    
  • 排序后的序列 - {5},{5.2},{5.7},{5.7.2}映射回节点 - A,C,B,D

这种方法的复杂性是O(n log(n)max_depth):

  • 构建树/步行树/构建密钥 - O(n)
  • sort是sort的复杂性(通常是O(num_elm log(num_elem))乘以比较键的复杂性,这取决于父子树的深度。这部分支配准备阶段所需的O(n)。

或者你可以构建树,按时间戳对每个级别进行排序,然后通过pre-order traversal将它们放回列表中,这样可以消除密钥比较的复杂性,但会破坏单一排序的要求。