当前位置:文档之家› 并行程序设计

并行程序设计

一、并行程序开发策略
1.自动并行化:有目的地稍许修改源代码
2.调用并行库:开发并行库
3.重新编写并行代码:对源代码做重大修改
二、并行编程模式
1.主从模式(任务播种模式):将待求解的任务分成一个主任务(主进程)和一些子任务
(子进程)。

所考虑的因素是负载均衡,一般可以采用静态分配和动态分配两种方法。

2.单程序流多数据流(SPMD):并行进程执行相同的代码段,但操作不同的数据。

3.数据流水线:将各个计算进程组成一条流水线,每个进程执行一个特定的计算任务。

4.分治策略:将一个大而复杂的问题分解成若干个特性相同的子问题。

三、并行程序的编程过程(PCAM过程)
1.任务划分(Partitioning)
2.通信分析(Communication)
3.任务组合(Agglomeration):增加粒度和保持灵活性
4.处理器映射(Mapping):映射策略、负载均衡、任务的分配与调度(静态和动态)
动态调度:基本自调度(SS)、块自调度(BSS)、指导自调度(GSS)、因子分解调度(FS)、梯形自调度(TSS)、耦合调度(AS)、安全自调度(SSS)、自适应耦合调度(AAS)
串匹配问题是计算机科学中的一个基本问题,在文字编辑、图像处理等利于都得到了广泛的应用,串匹配算法在这些应用中起到至关重要的作用。

因此研究快速的串匹配算法具有重要的理论和实际意义。

KMP是一种改进的字符串模式匹配的算法,他能够在o(m+n)时间复杂度内完成字符串的模式匹配算法。

本文将详细的介绍KMP算法的思想,串行及并行实现。

一、KMP算法思想
1、问题描述
给定主串S[0...n-1]、模式串T[0...m-1],其中m<=n。

在主串S中找出所有模式串T的起始位置。

2、算法思想
令指针i指向主串S,指针j指向模式串T中当前正在比较的位置。

令指针i和指针j指向的字符比较之,如两字符相等,则顺次比较后面的字符;如不相等,则指针i不动,回溯指针j,令其指向模式串T的第pos个字符,使T[0...pos-1] == S[i-pos, i-1],然后,指针i和指针j所指向的字符按此种方法继续比较,知道j == m-1,即在主串S中找到模式串T为止。

从算法的思想思想中我们可以看出,其算法的难点在于如何求出指针j的回溯值,即:当指针j回溯时,j将指向的位置,我们几位next[j]。

下面我们首先对kmp的算法做出详细的描述。

二、KMP算法描述
输入:主串S[0...n-1], 模式串T[0...m-1]
输出:m[0...n-1],当m[i] = 1时,则主串S中匹配到模式串,且i为起始位置
begin
i = 0;j = 0;
while(i < n)
if(S[i] != T[j])
j = next[j]
if( j == -1)
i++ j++
endif;
contiue;
endif
if (j == m-1)
m[i-j+1] = 1
j = -1
i = i-j+1
endif
i++ j++
end while
end
在上面的算法描述中,next函数的编写为整个算法的核心,设计出快速正确的next函数也为KMP算法的重中之重。

如何设计我们的next函数呢,我们利用递推思想:
1)令next[0] = -1,(为什么要等于-1呢,从上面的算法可以看出,当next[j] == -1时,证明字符串匹配要从模式串的第0个字符开始,且第0个字符并不和主串的第i个字符相等,i指针向前移动。

)2)假设next[j] = k ,说明T[0..k-1] == T[j-k...j-1]
3) 现在我们来求next[j+1]
3.1 当T[j] == T[k]时,说明T[0..k] == T[j-k..j],这时分为两种情况讨论:
3.1.1 当T[j+1] != T[k+1],显然
next[j+1] = k+1;
3.1.2 当T[j+1] == T[k+1],当这两个字符相等时,说明T[k+1]和T[j+1]一样,都不和主串的字符相匹配,因此:
m = k+1, j=next[m] 直到T[m] != t[j+1]
next[j+1] = m
3.2 当T[j] != T[k]时,我们必须在T[0..k-1]中找到next[j+1],这时:
k = next[k],直到T[j] ==T[k]
next[j+1] = next[k]
这样我们就通过数学中递推的方式求得了匹配串T的next函数。

三、串行实现
有了以上的算法描述,我们可以编写我们的kmp串行实现,本文不想黏贴过多的代码,仅仅给出next 函数的实现:
1: int *get_next(char *match_string, int match_string_length){
2:
3: int *next;
4: int next_index;
5:
6: int i;
7:
8: next = (int *)my_malloc(sizeof(int) * match_string_length);
9:
10: next[0] = -1;
11: i =0;
12: next_index = -1 ;
13:
14: while(i < match_string_length){
15:
16: if(next_index == -1 || match_string[next_index] == match_string[i]){//对应于3.1
17: i++;
18: next_index++;
19:
20: if(match_string[i] != match_string[next_index])//对应于3.1.1
21: next[i] = next_index;
22: else//对应于3.1.2
23: next[i] = next[next_index];
24: }
25: else//对应于3.2
26: next_index = next[next_index];
27: }
28:
29: return next;
30: }
四:并行算法
现在我们考虑如何将KMP算法并行化,我们很容易考虑到得是将主串S平均分成P段(假设有p个处理器),每个处理器处理其中的一段。

但这时要考虑一个问题,那就是如何处理每段字符串最后m-1个子字符串的匹配问题,因为这m-1个字符可能会和其后一段的前t个字符共同构成模式串。

我们首先考虑到得是每个处理器将其负责字符串的后m-1个字符的字串发送给其后面的处理器,但这样会造成通信过大的问题,每个处理器都要发送m-1个字符。

如何减少处理器间的通信呢?起始我们只需发送和模式串前t 个字符想匹配的t个字符就可以了。

这样就减少了进程间的通信。

其算法描述如下:输入:主串T[0...n-1],模式串S[0...m-1]
输出:m[0...n-1],当m[i] = 1时,则主串S中匹配到模式串,且i为起始位置
条件:t个处理器
1)p0读取主串和模式串,将模式串广播到起到所有的处理器中,并将主串分段发送到其对应的处理器中
2)处理器并行计算next函数,这样每个处理器都有统一的next函数和模式串
3)处理器p0 ,p1,...,pt-1并行计算各自负责字符串的后m-1个字符的字串和模式串的最小匹配串,并将最小匹配串发往下一个处理器
4)处理器接收上个处理器发送的字符串,并和本身的字符串合并成一个新的字符串
5)各处理器并行计算匹配结果m
6)处理器p0对各处理器的匹配结果进行整合,得到最终结果。

因为kmp并行算法相对简单,也没有用到新的MPI函数,这里不列出其并行实现代码。

相关主题