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=
和B={A_1,…,A_m}
。(它们也可以被视为集合){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的顺序中,而a_1
在b的顺序中。现在假设b_1>b_2
和a_1=b_1
根据a和b的相等运算符。在这种情况下,我认为您无法创建满足子列表顺序要求的组合列表 无论如何,有一种算法可以做到这一点a_2=b_2
这个算法在最坏的情况下是List=。。。 列表blist=。。。 List mergedList=新的SomeList(列表); int-mergePos=0; 对于(B:blist){ 布尔值=false; 对于(int i=mergePos;i
,在最好的情况下是O(N**2)
(我正在浏览一些Java实现细节……比如组合列表迭代和插入,而不会带来严重的复杂性损失……但我认为在这种情况下可以做到。) 该算法忽略了我在第一段中提到的病理学和其他病理学;例如,B的一个元素可能“等于”A的多个元素,反之亦然。为了处理这些问题,算法需要将每个O(N)
与合并列表中不是b实例的所有元素进行检查。这使得算法b
处于最佳状态。我认为你做得不比O(N*M)好,尽管我很高兴错了 在这种情况下,我会这样做:O(N**2)
- 以A的第一个(剩余)元素为例
- 在B里找它。
- 如果在B中找不到,请将其移动到输出
- 如果你确实在B中找到了它,那么把所有的东西从B移到并包括匹配项,然后从A中删除副本
- 重复上述步骤,直到A为空
- 将B中剩余的任何内容移动到输出
从示例中可以看出,该操作不能重复。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,d,e”必须位于“c”和“f”结束的位置之间。”-在这种情况下,可能会创建两个链表。第一个4,5,6,1
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)