#include <iostream>
using namespace std;
#include <vector>
#include <string>
#include <set>
#define N 10
//一个字符串的类 存放主串模式串
class HString{
public:
string ch;//主串模式串内容
int length;//主串模式串长度
HString()
{
ch=" ";
length=0;
}
};
vector<int> Get_Next(const HString& child)
{
int i=0;
int j=-1;
vector<int> next(child.length+1,-1);
while(i<child.length)
{
//匹配成功或者特殊情况 继续算下一个位置的next值
if(j==-1 || child.ch[i]==child.ch[j])
{
i++;
j++;
next[i]=j;
}
//匹配失败 继续找前缀的前缀匹配
else
{
j=next[j];
}
}
return next;
}
int KMP_compare(const HString& parent,const HString& child)
{
//KMP核心 next数组
//可以返回一个vector<int>类型 传入的是一个HString类
vector<int> next=Get_Next(child);
int i=0;
int j=0;
while(i<parent.length && j<child.length)
{
//如果匹配成功或者特殊情况 继续向前匹配
if(j==0 || parent.ch[i]==child.ch[j])
{
i++;
j++;
}
else
{
j=next[j];
}
}
if(j==child.length)
{
return i-child.length+1;
}
else
{
return 0;
}
}
//用父子串命名
bool Virus_Check(const HString& parent,const HString& child)
{
//首先解决什么与什么比较的问题
//m长度的病毒串去比较n长度的人类串 问题在于 一条病毒串有很多种情况(DNA循环结构)
//可以将病毒串复制一份 接在原串的后面 这样一来 去依次截取固定长度 就能实现所有情况都找到
//用一个新变量存放胶合后的串
string tempVirus;
//实现复制 胶合
for(int i=0;i<child.length*2;i++)
{
//i%child.length 取值在0~length-1
//巧妙地使i在有效下标循环
tempVirus+=child.ch[i%child.length];
}
//然后就是从这个胶合出的串去 取出原病毒串长度的模式串
//举个例子吧 对于病毒串ABB来说 其实有ABB BBA BAB 三种情况
//变成 ABBABB后 从0取三 得ABB 从1取三 得BBA 从2取三 得BAB
//实现这个过程
for(int i=0;i<child.length;i++)
{
//一行代码搞定
string virus=tempVirus.substr(i,child.length);
//取完后 把这些都放在HString类中去 因为比较还是得用两个HString比
HString virus_h;
virus_h.ch=virus;
virus_h.length=virus.length();
//直接在这里比就行了 省的再遍历取出 然后比 多此一举
//传入主串 模式串 也就是const HString& 返回值应该为int 找到了会是一个具体数 可以用来判断
if(KMP_compare(parent,virus_h)!=0)
{
return true;
}
}
return false;
}
int main() {
//设置要比对的内容
//人类dna 用string容器
//使用了define 这里就可以任意修改数量
const string person[]={
"bbaabbba","aaabbbba","abceaabb","abaabcea","cdabbbab",
"cabbbbab","bcdedbda","bdedbcda","cdcdcdec","cdccdcce"
};
//病毒DNA
const string virus[] = {
"baa","bae","aabb","abcd","aacd",
"abcde","acc","cde","cced","aace"
};
//把他们依次存放进Hstring类中 之后比较
//因为数量较多 使用vector容器 将HString类型的数据存储
//声明空间需要N单元
vector<HString> person_h(N);
vector<HString> virus_h(N);
//放入容器
for(int i=0;i<N;i++)
{
person_h[i].ch=person[i];
person_h[i].length=person[i].length();
virus_h[i].ch=virus[i];
virus_h[i].length=virus[i].length();
}
set<pair<string, string>> outputSet; // 用于跟踪已输出的结果
//需要比较的是人DNA和病毒DNA的每一项
//也就是全要比一遍 使用两层遍历
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if (Virus_Check(person_h[i], virus_h[j]))
{
// 使用pair来表示匹配的样本DNA和匹配的病毒
pair<string, string> resultPair(person_h[i].ch, virus_h[j].ch);
// 检查是否已经输出过相同的结果
if (outputSet.find(resultPair) == outputSet.end()) {
cout << "检测样本DNA:" << resultPair.first << "\t匹配的病毒:" << resultPair.second << endl;
outputSet.insert(resultPair); // 添加到集合中
}
}
}
}
return 0;
}