Nakatsu演算法--C++實現
阿新 • • 發佈:2018-11-10
期末論文選的是最長公共子序列的其他解法,偶然發現Nakatsu演算法對於最長公共子序列求解速度很快。嘔心瀝血寫的程式碼=。=| 希望可以給以後想學習用Nakatsu演算法的朋友們一個參考。 注:Nakatsu求的是最佳匹配度,子序列可能所含字元不正確,但卻是基於Nakatsu演算法的最佳匹配,求得的最長公共子序列的長度是一定對的。(沒用使用STL容器,不是很熟練)
/****************************************** 程式碼說明: 本程式定義了二維動態陣列L[][]用來儲存Nakatsu演算法中計算相同字元對應位置的矩陣 最大值即不存在相等的字元 若L[][]對角線上任意一個位置為最大值,對角線上其餘位置也是最大值,即本條對角線上不存在最大公共子序列 *******************************************/ //Nakatsu求解的是基於自身演算法的最長公共子序列的最佳匹配度,在某些情況可能與最長公共子序列有所偏差,即長度一致,字元可能會偏差少許 #include <iostream> #include <string> #include <iomanip> using namespace std; void LCS_N(const string& a, const string& b) { unsigned int i = 0;//迴圈控制變數也當做L[][i]陣列列下標 unsigned int j = 0;//迴圈控制變數 unsigned int m = a.length();//短字串長度 unsigned int n = b.length();//長字串長度 unsigned p = m-1;//記錄最長子序列長度 unsigned int k=1;//L[k][]陣列行下標 unsigned int **L = new unsigned int *[m];//字元位置矩陣 for (i = 0; i < m; i++) L[i] = new unsigned int[m]; for (i = 0; i < m; i++)//將 下面的一條次對角線 初始化為最大值,對於unsigned int來說,-1,就是最大值 { j = i + 1; if (j < m) L[j][i] = -1; }//for for (j = 0; j < m; j++) L[0][j] = 0;//第0行初始化為0 for (unsigned int x=1;x<m;x++) { k=1; i=x; for(j=1;j<n&&i<m;j++)//匹配a[i]與b[j] { if(a[i]==b[j]||j>=L[k][i-1]) { L[k][i]=j; k++; i++; } } //結束迴圈時,L[k][i]可能未賦值,L[k][i-1]可能為正常的值 while(i<m)//如果未跳出迴圈,對這條對角線的剩餘元素賦值,由於L[k][i-1]或為最大值,或為正常值,因此可以直接將L[k][i-1]賦值給L[k][i] { L[k][i]=L[k][i-1]; i++; k++; } if(L[k-1][i-1]!=-1)//如果這條對角線最後一個元素不為最大值(即-1),說明找到完整對角線,跳出迴圈 break; p--; } for(i=0;i<m;i++)//輸出最長子序列位置(位置對應著長字串中的字元),即完整的對角線上的數列, { for(j=0;j<m;j++) cout<<setw(11)<<L[i][j]<< " "; cout<<endl; }//for cout<<"最長公共子序列長度為:"<<p<<endl;//輸出最長公共子序列長度 if(m-x!=0) { cout<<"最長公共子序列為:"; for(i=1,j=x;i<=p;i++,j++)//輸出最長公共子序列(最佳匹配) cout<<b[L[i][j]]; cout<<endl; } for (i = 0; i < k; i++)//釋放動態陣列空間 delete[] L[i]; delete[] L; } int main() { string a; string b; cout << "Please enter the first string:" << endl; cin >> a; cout << "Please enter the second string:" << endl; cin >> b; a = " " + a; b = " " + b; swap(a, b); LCS_N(a, b); return 0; }