Algorithm 合并两个缺少比较的列表的算法

Algorithm 合并两个缺少比较的列表的算法,algorithm,language-agnostic,Algorithm,Language Agnostic,我在寻找一种合并两个排序列表的算法, 但它们在一个列表的元素和另一个列表的元素之间缺少比较运算符。 得到的合并列表可能不是唯一的,但满足每个列表的相对排序顺序的任何结果都可以。 更准确地说: 给定: 列出A={A_1,…,A_m}和B={B_1,…,B_n}。(它们也可以被视为集合) 优先运算符这听起来像是使用退化形式的拓扑排序 编辑2: 现在使用一个组合例程: import itertools list1 = [1, 2, 'c', 4, 5, 'f', 7] list2 = ['a',

我在寻找一种合并两个排序列表的算法, 但它们在一个列表的元素和另一个列表的元素之间缺少比较运算符。 得到的合并列表可能不是唯一的,但满足每个列表的相对排序顺序的任何结果都可以。 更准确地说:

给定:

  • 列出A=
    {A_1,…,A_m}
    和B=
    {B_1,…,B_n}
    。(它们也可以被视为集合)

  • 优先运算符这听起来像是使用退化形式的拓扑排序

    编辑2:

    现在使用一个组合例程:

    import itertools
    
    list1 = [1, 2, 'c', 4, 5, 'f', 7]
    list2 = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    
    ibase = 0
    result = []
    
    for n1, i1 in enumerate(list1):
      for n2, i2 in enumerate(itertools.islice(list2, ibase, None, 1)):
        if i1 == i2:
          result.extend(itertools.islice(list2, ibase, ibase + n2))
          result.append(i2)
          ibase = n2 + ibase + 1
          break
      else:
        result.append(i1)
    result.extend(itertools.islice(list2, ibase, None, 1))
    
    print result
    

    将这两个列表连接起来就足够了吗?它确实保留了a元素和b元素的相对分类

    然后就是删除重复项的问题


    编辑:好的,在评论讨论之后(并且考虑到附加条件,
    a_i=b_i&a_j=b_j&a_i b_i,考虑到你所表达的问题,我感觉问题可能没有解决方案。假设你有两对元素
    {a_1,b_1}
    {a_2,b_2}
    其中
    a_1
    在a的顺序中,而
    b_1>b_2
    在b的顺序中。现在假设
    a_1=b_1
    a_2=b_2
    根据a和b的相等运算符。在这种情况下,我认为您无法创建满足子列表顺序要求的组合列表

    无论如何,有一种算法可以做到这一点

    List=。。。
    列表blist=。。。
    List mergedList=新的SomeList(列表);
    int-mergePos=0;
    对于(B:blist){
    布尔值=false;
    对于(int i=mergePos;i
    这个算法在最坏的情况下是
    O(N**2)
    ,在最好的情况下是
    O(N)
    (我正在浏览一些Java实现细节……比如组合列表迭代和插入,而不会带来严重的复杂性损失……但我认为在这种情况下可以做到。)

    该算法忽略了我在第一段中提到的病理学和其他病理学;例如,B的一个元素可能“等于”A的多个元素,反之亦然。为了处理这些问题,算法需要将每个
    b
    与合并列表中不是b实例的所有元素进行检查。这使得算法
    O(N**2)
    处于最佳状态。

    我认为你做得不比O(N*M)好,尽管我很高兴错了

    在这种情况下,我会这样做:

    • 以A的第一个(剩余)元素为例
    • 在B里找它。
      • 如果在B中找不到,请将其移动到输出
      • 如果你确实在B中找到了它,那么把所有的东西从B移到并包括匹配项,然后从A中删除副本
    • 重复上述步骤,直到A为空
    • 将B中剩余的任何内容移动到输出
    如果要检测A和B的不兼容顺序,请从步骤2中删除“(剩下的部分)”。搜索整个B,如果发现“太早”,则引发错误

    问题是,给定a的一个一般元素,没有办法在比线性时间更好的时间(以B的大小)在B中寻找它,因为我们所拥有的只是一个等式测试。但显然,我们需要以某种方式找到匹配项,并且(这是我挥挥手的地方,我无法立即证明它)因此,我们必须检查A的每个元素是否包含在B中。我们可以避免一系列比较,因为这两个集合的顺序是一致的(至少,我假设它们是一致的,如果不是,就没有解决方案)

    因此,在最坏的情况下,列表的交集是空的,并且A的元素顺序与B的任何元素都不可比。这需要N*M等式测试来建立,因此最坏情况的界限

    对于您的示例问题A=(1,2,c,4,5,f),B=(A,B,c,d,e,f),这给出了结果(1,2,A,B,c,4,5,d,e,f),我觉得很好。它在这个过程中执行24个相等测试(除非我不能计数):6+6+3+3+3。与A和B以相反的方式合并将产生(A,B,1,2,c,d,e,4,5,f),在这种情况下,具有相同数量的比较,因为匹配元素恰好位于两个列表中的相同索引处


    从示例中可以看出,该操作不能重复。merge(A,B)导致列表的顺序与merge(B,A)的顺序不一致。因此merge((merge(A,B),merge(B,A))未定义。通常,合并的输出是任意的,如果您使用任意顺序作为新的完整顺序的基础,您将生成相互不兼容的顺序。

    如果元素是可散列的,这可以在O(N)时间内完成,其中N是a和B中的元素总数

    def merge(A, B):
        # Walk A and build a hash table mapping its values to indices.
        amap = {}
        for i, a in enumerate(A):
            amap[a] = i
    
        # Now walk B building C.
        C = []
        ai = 0
        bi = 0
        for i, b in enumerate(B):
            if b in amap:
                # b is in both lists.
                new_ai = amap[b]
                assert new_ai >= ai  # check for consistent input
                C += A[ai:new_ai]    # add non-shared elements from A
                C += B[bi:i]         # add non-shared elements from B
                C.append(b)          # add the shared element b
                ai = new_ai + 1
                bi = i + 1
        C += A[ai:]  # add remaining non-shared elements from A
        C += B[bi:]  # from B
        return C
    
    A = [1, 2, 'c', 4, 5, 'f', 7]
    B = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    print merge(A, B)
    

    (这只是Anon算法的一个实现。请注意,您可以在不影响性能的情况下检查不一致的输入列表,并且不需要对列表进行随机访问。)

    假设我的列表是“1,2,c,4,5,f”和“a,b,c,d,e,f”。串联将使“1,2,c,4,5,f,a,b,c,d,e,f”.现在,“c”和“f”都是重复的,因此必须进行一些改组;在“4,5,d,e”中都必须介于“c”和“f”之间。你能提出一个具体的方法来实现这一点吗?假设我们有列表
    1,2,3,4
    4,5,6,1
    。结果应该是什么?这种情况是不可满足的,并且在实践中不会出现。理想情况下,如果可以检测到循环条件并引发错误,这种情况就会出现。“必须进行一些调整;因为“4,5,d,e”必须位于“c”和“f”结束的位置之间。”-在这种情况下,可能会创建两个链表。第一个
    def merge(A, B):
        # Walk A and build a hash table mapping its values to indices.
        amap = {}
        for i, a in enumerate(A):
            amap[a] = i
    
        # Now walk B building C.
        C = []
        ai = 0
        bi = 0
        for i, b in enumerate(B):
            if b in amap:
                # b is in both lists.
                new_ai = amap[b]
                assert new_ai >= ai  # check for consistent input
                C += A[ai:new_ai]    # add non-shared elements from A
                C += B[bi:i]         # add non-shared elements from B
                C.append(b)          # add the shared element b
                ai = new_ai + 1
                bi = i + 1
        C += A[ai:]  # add remaining non-shared elements from A
        C += B[bi:]  # from B
        return C
    
    A = [1, 2, 'c', 4, 5, 'f', 7]
    B = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    print merge(A, B)