Beiyou 22 Xintong: (13) 第 3 章 3.4 文字列実装 KMP アルゴリズム

北友22新通〜   

データ構造とアルゴリズムに関するコードと記事は、コースの進行状況に応じて毎週更新されます。 

Youyuan Xintong のさらに独占的なコードのロックを解除するために、作者に引き続き注目してください~

前の記事:

次の記事:

***イラスト***

1. このコードは、本の第 2 章の線形テーブルと 4.3.3KMP アルゴリズムを組み合わせて記述されています。

2. マッチング速度を高速化する基本的な理由:プレフィックスの部分文字列をマッチングする必要がありません

3.ヒープ領域に動的配列を適用する際のバッファの問題について:

        ヒープ領域を申請するたびに、システムは申請フォーム内の未使用のヒープ領域をデータバッファとして自動的に使用します。平たく言えば、システムは、入力しようとしているデータの領域を事前に予測し、データを再度入力すると、データがオーバーフローしますか。

        プログラムはこのようなことが起こることを非常に恐れているため、常に慎重にデータバッファを確保しており、データを入力するたびに、データは前回データを入力したときに生成されたバッファに入り、その後バッファは後ろに移動します。要求されたヒープ領域の下端に達すると、プログラムは警告を出しますので、もう少しヒープ領域を確保することを考慮しないと、データがオーバーフローします。そうすれば、文の下に小さな緑色の線が描画されます...それで! 適切にスペースを申請してください

4. KMP 関数の実装プロセスは BF アルゴリズムに似ており、BF を理解していれば当然 KMP も簡単に理解できるため、前に作成した getnextarray 関数に焦点を当てます。

***説明の終わり***

1. KMPアルゴリズムを実装したシーケンステーブル

KMP アルゴリズム部分:

template<class temp>
void seqlist<temp>::getnextarray(seqlist<temp>& t, int*& next)
{
	next = new int[t.getlength() + 10];
	/*如果写成next = new int[t.getlength() + 1]会有建议提示:
	“写入next时缓存区溢出”,原因如下:
	next动态数组缓冲区溢出动态数组基本全部被占满,数据缓冲区不够;
	所以应多给动态数组分配一点存储空间以增加缓存区容量*/
	next[1] = 0;
	next[2] = 1;
	int p = 1;
	for (int j = 3; j <= t.getlength(); ++j)
	{
		while (p > 1 && t.get(p) != t.get(j - 1))
			p = next[p];
		if (t.get(p) == t.get(j - 1))
			++p;
		next[j] = p;
	}
}

template<class temp>
int seqlist<temp>::KMP(seqlist<temp>& t)
{
	int* next;
	getnextarray(t, next);
	int i = 1, j = 1;
	while (i <= this->getlength() && j <= t.getlength())
	{
		if (get(i) == t.get(j))
		{
			i++; j++;
		}
		else if (!next[j])
		{
			i++; j = 1;
		}
		else
			j = next[j];
	}
	delete[]next;
	if (j > t.getlength())return i + 1 - j;
	else return -1;
}

コード部分と実行結果:

#include <iostream>
using namespace std;
#define N 100
template<class temp>
class seqlist
{
private:
	temp data[N];
	int length;
public:
	seqlist() { length = 0; }
	seqlist(temp a[], int n);
	int getlength() { return length; }
	void printlist();
	void insert(int i, temp x);
	temp del(int i);
	temp get(int i);
	int locate(temp x);
	void getnextarray(seqlist<temp>& t, int*& next);
	int KMP(seqlist<temp>& t);
};

template <class temp>
seqlist<temp>::seqlist(temp a[], int n)
{
	if (n > N)throw "数组长度超过顺序表最大长度";
	for (int i = 0; i < n; i++)
		this->data[i] = a[i];
	this->length = n;
}

template<class temp>
void seqlist<temp>::printlist()
{
	cout << "按序号依次遍历线性表中各个数据元素:" << endl;
	for (int i = 0; i < this->length; i++)
		this->data[i].print();
	cout << endl;
}

template<class temp>
void seqlist<temp>::insert(int i, temp x)
{
	if (this->length >= N)throw"上溢异常";
	if (i < 1 || i >= this->length + 1)throw"位置异常";
	for (int j = this->length; j >= i; j--)
		this->data[j] = this->data[j - 1];
	this->data[i - 1] = x;
	this->length++;
}

template<class temp>
temp seqlist<temp>::del(int i)
{
	if (this->length == 0)throw"下溢异常";
	if (i<1 || i>this->length)throw"位置异常";
	temp x = data[i - 1];
	for (int j = i; j < this->length; j++)
		data[j - 1] = data[j];
	this->length--;
	return x;
}


template<class temp>
temp seqlist<temp>::get(int i)
{
	if (i<1 || i>this->length)throw"查找位置非法";
	return this->data[i - 1];
}

template<class temp>
int seqlist<temp>::locate(temp x)
{
	for (int i = 0; i < this->length; i++)
		if (this->data[i] == x)return(i + 1);
	return 0;
}

template<class temp>
void seqlist<temp>::getnextarray(seqlist<temp>& t, int*& next)
{
	next = new int[t.getlength() + 10];
	/*如果写成next = new int[t.getlength() + 1]会有建议提示:
	“写入next时缓存区溢出”,原因如下:
	next动态数组缓冲区溢出动态数组基本全部被占满,数据缓冲区不够;
	所以应多给动态数组分配一点存储空间以增加缓存区容量*/
	next[1] = 0;
	next[2] = 1;
	int p = 1;
	for (int j = 3; j <= t.getlength(); ++j)
	{
		while (p > 1 && t.get(p) != t.get(j - 1))
			p = next[p];
		if (t.get(p) == t.get(j - 1))
			++p;
		next[j] = p;
	}
}

template<class temp>
int seqlist<temp>::KMP(seqlist<temp>& t)
{
	int* next;
	getnextarray(t, next);
	int i = 1, j = 1;
	while (i <= this->getlength() && j <= t.getlength())
	{
		if (get(i) == t.get(j))
		{
			i++; j++;
		}
		else if (!next[j])
		{
			i++; j = 1;
		}
		else
			j = next[j];
	}
	delete[]next;
	if (j > t.getlength())return i + 1 - j;
	else return -1;
}

int main()
{
	system("color 0A");
	char a[] = "hello world";
	char b[] = "good";
	char c[] = "ello";
	seqlist<char>seqa(a, strlen(a));
	seqlist<char>seqb(b, strlen(b));
	seqlist<char>seqc(c, strlen(c));
	cout << seqa.KMP(seqa) << endl;//1
	cout << seqa.KMP(seqb) << endl;//-1
	cout << seqa.KMP(seqc) << endl;//2
	return 0;
} 

「ブロガーさん、メインタイトルとコンテンツが抜けていませんか?」

「ダメダメダメダメ!」(自信満々)(逃げる)

起きたら更新します… 

おすすめ

転載: blog.csdn.net/bc202205/article/details/130220095