KMP算法实现
昨天看到一个快速字符串查找的思路---KMP,感觉挺有意思的,就实现来试试,下面是代码:
- 环境: windows7 + Qt Creator3.4.2 + Qt5.5.0
- 如果想看算法解释过程的请看这里KMP原理
main.cpp:
#include "mainwindow.h"
#include <QApplication>
#define SRC "abcdefghigklmnopqrstuvwxyz"
#define MATCHSTR "yzz"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString src, SubStr;
src = SRC;
SubStr = MATCHSTR;
MainWindow w(src, SubStr);
w.show();
qDebug()<<"matcher num = "<<w.Matcher();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "string.h"
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QString &src, QString &sub);
~MainWindow();
int Matcher();
private:
void CalMatchTable();
private:
QString SrcStr, SubStr;
int *Matchlen;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QString &src, QString &sub) :
SrcStr(src),
SubStr(sub)
{
Matchlen = new int[SubStr.size()];
//这里需要bzero?
Matchlen[0] = 0;
// bzero();
memset(Matchlen, 0, sizeof(int)*SubStr.size());
}
MainWindow::~MainWindow()
{
if(Matchlen != NULL)
{
delete Matchlen;
Matchlen = NULL;
}
}
/**
* return: 第一次匹配到的起始位置或者-1(没有匹配到)
*/
int MainWindow::Matcher()
{
int index;
CalMatchTable();
for(int j = 0; j<SubStr.size(); j++)
qDebug("SubStr %d = %d\n", j, Matchlen[j]);
for(int i=0; i<SrcStr.size(); )
{
index = 0;
if(SrcStr.at(i) != SubStr.at(0))
{
i++;
continue;
}
else
{
if( SubStr.size() == 1 )
{
return i;
}
for(int j=1; j<SubStr.size(); j++ )
{
//防止访问源字符串越界
if(i+j >= SrcStr.size())
return -1;
if(SrcStr.at(i+j) == SubStr.at(j))
{
if( (j+1) == SubStr.size() )
{
return i;
}
else
{
continue;
}
}
else
{
//移动位数 = 已匹配的字符数 - 对应部分的匹配值
index = j - Matchlen[j-1];
i += index;
break;
}
}
}
}
return -1;
}
/**
* 计算出部分匹配值(partial Match Table)
*/
void MainWindow::CalMatchTable()
{
int num;
QString substr;
QStringList prefix, suffix;
for( int i=1; i<SubStr.size(); i++ )
{
substr = SubStr.left(i+1);
qDebug()<<"substr = "<<substr;
//计算出前后缀
//j: 1 -> strlen(substr)
for(int j=1; j<substr.size(); j++)
{
prefix << substr.left(j);
suffix << substr.right(substr.size()-j);
}
num = prefix.size();
//前后缀对比共有元素,并对Matchlen数组赋值
for(int k=0; k<num; k++)
{
if(prefix.at(k) == suffix.at(num-1-k))
{
// Matchlen[i]++;//这里可以么?
Matchlen[i] = Matchlen[i] + 1;
}
}
substr.clear();
prefix.clear();
suffix.clear();
}
}