如果A=(a1,a2,...,am)和B=(b1,b2,...,bn)是两个有序的升序数组,合并数组A和B就行形成一个新的升序数组包含A和B的有所有元素,假设A=(2,4,11,12,14,35,95,99),B=(6,7,9,25,26,31,42,85,87,102,105).
如果合并A和B的数组,串行算法会遍历两个数组,然后将数组元素存到数组C中,开始时设置两个指针,分别指向数组A和B的每一个元素,接下来每个移动A或者B的一个指针。如此遍历时间复杂度为O(m+n)。其伪代码如下
串行算法:
输入A和B
输出C
1. set a[m+1] = +INF,b[n+1] = +INF.
2. set i = 1, j = 1 , k = 1
3. while k <= m+n do
4. If a[i] < b[j] do
c[k] = a[i] and i = i+1
else
c[k] = b[j] and j = j + 1;
endif
5. k = k + 1;
6. End While
7. END
下面分析其并行算法(注意本算法有一个局限性,只适用于最终合并的C中没有重复元素的情况)
定义: rank(x:A)指数组A中不大于x的元素个数, rank(6:A)=2, rank(25:A)=5.
rank(B:A)为数组(r1,r2,..., rn),其中ri=rank(B[i]:A)
对于上面给出的A和B数组,可以得到如下。
rank(B:A)=(2,2,2,5,5,5,6,6,6,8,8)
rank(B:B)=(1,2,3,4,5,6,7,8,9,10,11)
rank(A:B)=(0,0,3,3,3,6,9,9)
rank(A:A)=(1,2,3,4,5,6,7,8)
进一步分析rank(x:A U B)是指AUB中不大于x的元素数量,因此rank(x:AUB=rank(X:A)+rank(x:B),进一步:
rank(A:AUB)= rank(A:A)+rank(A:B) = (0,0,3,3,3,6,9,9) + (1,2,3,4,5,6,7,8)
= (1,2,6,7,8,12,16,17)
rank(B:AUB)= (3,4,5,9,10,11,13,14,15,18,19)
从rank(A:AUB)中我们可以知道A中每个元素中C中的位置,即C[1] = 2, C[2] = 4, C[6] = 11, C[17] = 99. 对B中元素可以rank(B:AUB)确定其中C中的位置
上面介绍了基本的算法思想,下面来分析该算法,并将其并行化。
下面给出该算法的伪代码
1. For i = {1, 2, .. , m} and j = {1 , 2 , ..., n} do in parallel
2. find rank (ai:A) and find rank(bj:B)
3. find rank (ai:B) and find rank(bj:A)
4. END parallel
5. Denote rank(A:B)and rank(B:A).
6. RA = rank(A:A)+rank(A:B)
7. RB = rank(B:A)+rank(B:B)
8. for i = 1 to m do in parallel
9. C[RAi] = A[i]
10. End Parallel
11. for i = 1 to n do in parallel
12. C[RBi] = B[i]
13. End Parallel
14. END
时间复杂度分析:
由于A和B是有序的,我们可以使用二分搜索法利用一个处理器在O(log(m))的时间内完成求rank(x:A),相似地rank(x:B)的复杂度为O(log(n)).
因此1~4步使用m+n个处理器可以在O(log(n))(假定n >= m)的时间内完成, 其余步骤都可以在O(1)的时间内完成,因此该算法的时间复杂度为O(Log(n)), 需要使用的处理器个数为m+n.