AC算法的高效C++实现



终于用C++实现了AC算法的多模式匹配,代码贴上如下:


//构造ac对象的时候,输入的模式串集合以“end”作为结束标志
#include<iostream>
#include<vector>
#include<string>
using namespace std;

//该结构是状态节点,只负责记录当前节点相关的信息
class Node{
public:
 char whichCauseToThisStatus;//哪一个动作导致了当前节点的出现
 int NodeStatus;//当前节点状态
 int previewNodeStatus;//前一节点状态
 bool isEndStatus;//是否是终止状态
 string maxChildString;//该节点串中前面除去第一个字符的最大子串
 string outputStringOfThisStatus;//如果当前节点是终止节点的话,当前节点应该要输出的内容
 int whereToGoWhenFailed;//当失配的时候的跳转状态
public:
 Node(){//构造函数
  setNode(0, -1, false, "", "", -1);
 }
 Node(int NS, int PRS, bool IES, string MCS, string OSOTS, int WTGWF){//构造函数
  setNode(NS,PRS,IES,MCS,OSOTS,WTGWF);
 }
 void setNode(int NS, int PRS, bool IES, string MCS, string OSOTS, int WTGWF){
  NodeStatus = NS;//默认值为根节点
  previewNodeStatus = PRS;//默认前一个节点的状态是根节点
  isEndStatus = IES;//默认节点不是终止状态
  maxChildString = MCS;//默认最大子串为空
  outputStringOfThisStatus = OSOTS;//当前是输出节点的输出结果
  whereToGoWhenFailed = WTGWF;//默认跳转是为根节点
 }
 friend ostream& operator<<(ostream&cout, Node&n){

  cout << "哪一个字符导致了当前的节点:" << n.whichCauseToThisStatus << endl;
  cout << "当前节点状态:" << n.NodeStatus << endl;
  cout << "前一个节点状态:" << n.previewNodeStatus << endl;
  cout << "当前节点是否是终止状态:" << n.isEndStatus << endl;
  cout << "最大子串:" << n.maxChildString << endl;
  cout << "如果是终止状态的输出字符串:" << n.outputStringOfThisStatus << endl;
  cout << "失配的时候应该要回溯到哪里:" << n.whereToGoWhenFailed << endl;
  return cout;
 }
};

//该结构是每个当前状态indexNode的一次操作结果,可以认为是领域关系,
//重要的是要判断该状态下是否存在某操作的结果,如果不存在就添加进去,存在的话就切换当前状态为下一个状态
class indexNode{
public:
 int indexStatus;//当前状态
 char ch;//一次操作
 int nextStatusOfIndexStatus;//操作结果转移到的状态
public:
 indexNode(){
  indexStatus = 0;
  ch = '~';
  nextStatusOfIndexStatus = 0;
 }
 indexNode(int a, char b, int c){
  indexStatus = a;
  ch = b;
  nextStatusOfIndexStatus = c;
 }
 void set(int a, char b, int c){
  indexStatus = a;
  ch = b;
  nextStatusOfIndexStatus = c;
 }
 bool operator==(const indexNode&iN){
  return indexStatus == iN.indexStatus&&ch == iN.ch;
 }
 bool operator!=(const indexNode&iN){
  return indexStatus != iN.indexStatus&&ch != iN.ch;
 }
};

//ac算法类
class AC{
public:
 vector<Node>vecNode;//vecNode向量存储了各个状态的信息
 vector<string>vecString;//vecString存储了模式串集合
 vector<indexNode>vecIndexNode;//存储了状态机的vector,现在的问题是要能够保证能够访问到该vector里面的每一个重复状态,可以使用find函数进行查找
public:
 AC(){
  //完成模式串集合的输入
  vecNode.reserve(100);
  vecString.reserve(20);
  string s = "";
  cout << "请输入模式串集合:";
  while (1){
   cin >> s;
   if (s == "end" || s == "END"){
    break;
   }
   vecString.push_back(s);
  }
  // //输出结果
  // int k = 0;
  // for (vector<string>::iterator i = vecString.begin(); i != vecString.end(); i++){
  //  cout <<k<< ","<<vecString[k] << endl;
  //  k++;
  // }

  //AC算法需要处理一下,每个模式串,从而确定下状态树
  Node*p = NULL;//p用来新建一个状态
  string temp;//临时string
  int status = 0;//当前状态为0,status只能加加,该状态是新建的状态
  int tempchar = 0;//对应于一个模式串处理到了哪一个位置
  int jumpStatus = 0;//跳转状态
  vector<indexNode>::iterator VINI;
  //存储0状态
  vecNode.push_back(Node());
  for (vector<string>::iterator i = vecString.begin(); i != vecString.end(); i++){//对于每一个模式串

   temp = *i;
   jumpStatus = 0;//对于每一个模式串的处理都是从状态0开始跳转
   tempchar = 0;//当前处理的位置是0
   for (string::iterator j = temp.begin(); j != temp.end(); j++,tempchar++){//对于每一个模式串开始处理其字符

    //如果在已经建立好了的表里面查找到了相应的字符
    if ((VINI=find(vecIndexNode.begin(), vecIndexNode.end(), indexNode(jumpStatus, *j, 0)))!=vecIndexNode.end()){

     jumpStatus = VINI->nextStatusOfIndexStatus;
     if (j + 1 == temp.end()){//如果当前字符是最后一个字符的话而且被在串中查找到了的话,就要更改此节点的信息
      vecNode[jumpStatus].isEndStatus = true;
      vecNode[jumpStatus].outputStringOfThisStatus = temp;
     }
    }
    else{

     //否则的话
     status++;//第一次的时候,新建的一个状态为1
     //新建出一个节点状态
     p = new Node();
     p->whichCauseToThisStatus = *j;//导致当前节点的字符的赋值
     if (j + 1 == temp.end()){//如果当前字符是最后一个字符的话,就需要设置输出字符串
      p->setNode(status, jumpStatus, true, temp.substr(1, tempchar), temp, 0);
     }
     else{//否则的话不需要设置输出字符串
      p->setNode(status, jumpStatus, false, temp.substr(1, tempchar), "", 0);
     }
     //节点设置好了之后就添加进去
     vecNode.push_back(*p);

     //并且在vecIndexNode里面注册一个信息
     vecIndexNode.push_back(indexNode(jumpStatus,*j,p->NodeStatus));

     //添加完毕的话就修改当前的跳转状态
     jumpStatus = p->NodeStatus;
    }
   }
  }


  //状态树确定正确
  //AC算法需要处理一下fail状态下的wheretogowhenfail
  //for (vector<indexNode>::iterator i = vecIndexNode.begin(); i != vecIndexNode.end(); i++){
  //
  // if (i->indexStatus == 0){
  //  vecNode[i->nextStatusOfIndexStatus].whereToGoWhenFailed = 0;
  // }
  //}

  int toUseAsTmpStatus = 0;
  vector<indexNode>::iterator VI;
  for (int i = 1; i < vecNode.size(); i++){

   if (vecNode[i].previewNodeStatus != 0){
    if (vecNode[vecNode[i].previewNodeStatus].whereToGoWhenFailed == 0){//如果当前关系的前一个节点是最靠近0节点的节点的话
     VI = find(vecIndexNode.begin(), vecIndexNode.end(), indexNode(0, vecNode[i].whichCauseToThisStatus, 0));
     if (VI != vecIndexNode.end()){//说明找到了这样一个节点
      vecNode[i].whereToGoWhenFailed = VI->nextStatusOfIndexStatus;
     }
     else{//如果没有找到的话
      vecNode[i].whereToGoWhenFailed = 0;
     }
    }
    else{//如果不是最靠近0节点的话
     toUseAsTmpStatus = vecNode[vecNode[i].previewNodeStatus].whereToGoWhenFailed;
     VI = find(vecIndexNode.begin(), vecIndexNode.end(), indexNode(toUseAsTmpStatus, vecNode[i].whichCauseToThisStatus, 0));
     if (VI != vecIndexNode.end()){//如果存在

      vecNode[i].whereToGoWhenFailed = VI->nextStatusOfIndexStatus;
     }
     else{//如果不存在就要从0状态去查找
      VI = find(vecIndexNode.begin(), vecIndexNode.end(), indexNode(0, vecNode[i].whichCauseToThisStatus, 0));
      if (VI != vecIndexNode.end()){//找到了
       vecNode[i].whereToGoWhenFailed = VI->nextStatusOfIndexStatus;
      }
      else{//没找到
       vecNode[i].whereToGoWhenFailed = 0;
      }
     }
    }
   }
  }

  //含有跳转信息
  //输出状态树
  cout << "=====================================================================\n状态树结果:" << endl;
  for (vector<indexNode>::iterator i = vecIndexNode.begin(); i != vecIndexNode.end(); i++){
  
   cout << "(" << i->indexStatus << "," << i->ch << "," << i->nextStatusOfIndexStatus << ")" << endl;
  }
  cout << "=====================================================================\n状态树结果:" << endl;
  for (vector<Node>::iterator i = vecNode.begin(); i != vecNode.end(); i++){
  
   cout << *i << endl;
  }
 }

 //AC算法的处理已经完成
 //等待被处理字符串进行处理

 void checkMaxChildString(string s){//s是待检测模式串

  vector<string>::iterator VII;
  for (int i = 1; i < s.size();i++){

   VII = find(vecString.begin(), vecString.end(), s.substr(i));
   if (VII != vecString.end()){//如果找到了的话,就输出
    cout << *VII << endl;
   }
  }
 }

 void checkStrings(string text){//进行模式匹配,text是要被用来匹配的模式

  vector<indexNode>::iterator VI;
  int jumpStatus = 0;
  for (string::iterator i = text.begin(); i != text.end();){

   VI = find(vecIndexNode.begin(), vecIndexNode.end(), indexNode(jumpStatus, *i, 0));//查找是否存在当前关系

   if (VI == vecIndexNode.end()){//如果不存在当前关系

    if (jumpStatus != 0){
     jumpStatus = vecNode[jumpStatus].whereToGoWhenFailed;//如果当前关系不存在的话,就转到当前状态的下一个跳转状态
    }
    else{
     i++;
    }
   }
   else{//如果存在当前关系,就要判断当前jumpStatus是否是终止状态如果是的话,就要输出该终止态应该要输出的结果
    
    jumpStatus = VI->nextStatusOfIndexStatus;
    if (vecNode[jumpStatus].isEndStatus){//如果该操作的下一个状态是一个终止状态,就要输出其结果

     cout << vecNode[jumpStatus].outputStringOfThisStatus << endl;
     //输出完毕之后还需要对该节点的最大子串进行检查,看最大子串是不是一个模式串,而不是对最大子串进行匹配处理
     checkMaxChildString(vecNode[jumpStatus].outputStringOfThisStatus);
    }
    //不管是不是终止状态都要字符指针向下移动
    i++;
   }
  }
  //cout << text << endl;
 }
};



void main(){

 AC ac;
 ac.checkStrings("dcbabccbcabcdaaccbadf");
 //ac.checkStrings("aaa");
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值