算法导论——最长公共子序列

来源:互联网 发布:网络招聘平台有哪些 编辑:程序博客网 时间:2024/06/14 07:04

一、算法设计与分析:

设计LCS-LENGTH算法,概算福接受两个序列X[1..m]、Y[1...n]为输入。它将c[i,j]的值保存在表c[0…m,0…n],并按照行主序计算表项。过程维护一个表b[1…m,1…n],帮助构造最优解。B[i,j]指向的表项对应计算c[i,j]时所选择的子问题最优解。伪代码如下:

LCS-LENGTH(X,Y)m=X.length;n=Y.length;let b[1…m,1…n] and c[0…m,0…n] be new tablesfor i=1 to m    c[i,0]=0;for j=0 to n    c[0,j]=0;for i=1 to n    for j=1 to n        ifX[i]==Y[j]           c[i,j]=c[i-1,j-1]+1;           b[i,j]=’y’;        elseif c[i-1,j]>=c[i,j-1]               c[i,j]=c[i-1,j];               b[i,j]=’u’;            elsec[i,j]=c[i,j-1];               b[i,j]=’l’;return c and b;

二、算法实现

#include<iostream>#include <iomanip>#define MAXX 1000#define MAXY 1000#include<stack>using namespace std;int LCS_LENGTH(char X[], char Y[], int **c, char **b);void PRINT_LCS(char **b, char X[], int i, int j);//递归void PRINT_LCS2(char **b, char X[], int i, int j);//非递归int main() {int len;int **c = new int*[MAXX+1];for (int i = 0; i <= MAXX; i++) {c[i] = new int[MAXY+1];}char **b = new char*[MAXX+1];for (int i = 0; i <=MAXX; i++){b[i] = new char[MAXY+1];}char ch;//char X[] = {'0','A','B','C','B','D','A','B'};//char Y[] = {'0','B','D','C','A','B','A'};char *X = new char[MAXX + 1];char *Y = new char[MAXX + 1];X[0] = '0'; Y[0] = '0';for (int i = 1; i <=MAXX; i++){X[i] = 'A'+rand()%26;}for (int j = 1; j <= MAXY; j++) {Y[j] = 'A'+rand()%26;}len=LCS_LENGTH(X,Y,c,b);cout << "LCS长度为:"<< len << endl;cout << "一个LCS为:";//PRINT_LCS(b, X, MAXX, MAXY);//递归输出,数据量大时递归栈溢出PRINT_LCS2(b, X, MAXX, MAXY);//迭代输出cout << endl;return 0;}int LCS_LENGTH(char X[], char Y[], int** c, char **b) {int i, j;for (i = 0; i <= MAXX; i++) {c[i][0] = 0;}for (j = 0; j <= MAXY; j++) {c[0][j] = 0;}for (i = 1; i <= MAXX; i++) {for (j = 1; j <= MAXY; j++) {if (X[i] == Y[j]) {c[i][j] = c[i - 1][j - 1] + 1;b[i][j] = 'y';}else {if (c[i - 1][j] >= c[i][j - 1]) {c[i][j] = c[i-1][j];b[i][j] = 'u';}else {c[i][j] = c[i][j - 1];b[i][j] = 'l';}}}}return c[MAXX][MAXY];}//递归输出void PRINT_LCS(char **b, char X[],int i, int j) {if (i == 0 || j == 0)return;if (b[i][j] == 'y') {PRINT_LCS(b,X,i-1,j-1);cout << X[i];}else {if (b[i][j] == 'u') {PRINT_LCS(b, X, i - 1, j);}elsePRINT_LCS(b,X,i,j-1);}}//非递归输出void PRINT_LCS2(char **b, char X[], int i, int j) {stack<char> lcs;while (!(i==0 || j==0)) {if (b[i][j] == 'y') {lcs.push(X[i]);//cout << X[i];i--;j--;}else {if (b[i][j] == 'u') {i--;}else {j--;}}}while (!lcs.empty()) {cout << lcs.top();lcs.pop();}}

三、算法结果分析

首先采用算法导论书上例子进行测试:即X={A,B,C,B,D,A,B},Y={B,D,C,A,B,A}

程序运行结果如下:


可见运行结果与预期一致。

'A'+rand()%26随机生成两个10000个字母的序列,运行结果如下:



四、总结

该算法采用自底向上的动态规划算法,时间复杂度为O(mn),空间复杂度为也为O(mn),如果采用两个二维数组存储b和c,当序列较大时出现栈溢出的问题,所以采取在堆上分配二维数组空间的办法以处理较大的数据量。

当数据量比较大时递归的输出方法将会出现栈溢出问题,所以采取非递归的输出算法。


0 0
原创粉丝点击