創建一個字符文件。從鍵盤輸入字符文件名以及子串,程序首先求取子串的nextval數組,而後用改進KMP算法在文件中查找子串,最後在屏幕上顯示輸出子串在文件中的匹配次數。若文件中無子串,輸出匹配次數爲0。ios
串、改進KMP算法、字符串查找、模式匹配。算法
用字符數組,定義兩個字符串:主串s和子串t。主串經過文件輸入保存,子串經過控制檯輸入。數組
串的模式匹配算法,與子串定位的算法概念相同,即在主串s中查找子串t(稱爲模式)第一次出現的起始位置。
經過改進KMP算法,能夠使得文件一次掃描的條件下,不遺漏地找到全部子串與主串成功匹配的位置下標,並記錄成功匹配的總次數。數據結構
#include<iostream> #include<fstream> using namespace std; void read(char *filename,char *s) //讀取數據,filename代入不一樣的文件名,s爲主串 { char c; int i = 0; ifstream infile(filename); if (!infile) //打開文件失敗輸出提示信息 { cout << "file open error!" << endl; exit(0); } while (1) //讀入字符,保存在主串中 { infile >> c; if (infile.eof()) break; s[i] = c; i++; } s[i] = '\0'; cout << "主串爲: "; //輸出主串 for (i = 0; i < strlen(s); i++) cout << s[i]; cout << endl; infile.close(); } void get_next(char *t, int next[]) //求next數組,t爲子串 { int j, k; next[0] = k = -1; j = 1; while (j <= strlen(t) + 1) //爲避免文件回溯,求到next[m]值 { if (k == -1 || t[j - 1] == t[k]) next[j++] = ++k; else k = next[k]; } } void get_nextval(char *t, int nextval[], int next[]) //求nextval數組,t爲子串 { int j, k; nextval[0] = k = -1; j = 1; while (t[j]) { if (k == -1 || t[j - 1] == t[k]) if (t[++k] == t[j]) nextval[j++] = nextval[k]; else nextval[j++] = k; else k = nextval[k]; } nextval[strlen(t)] = next[strlen(t)]; //nextval[m]即爲next[m]的值 } int index_kmp(char *s, char *t, int nextval[], int &num) /*KMP算法:子串的模式匹配,s爲主 串,t爲子串,num記錄匹配的次數*/ { int i, j, flag = 1, location; /*flag爲標量,第一次匹配時flag爲1,不然flag爲 0,location記錄第一次匹配的位置下標*/ i = j = 0; while (s[i] && (j == -1 || t[j])) { if (j == -1 || s[i] == t[j]) { i++; j++; } else j = nextval[j]; if (!t[j]) { if (flag == 1) //第一次匹配,location記錄匹配的位置下標 { location = i - j; flag = 0; cout << "子串出現的位置分別爲: "; } cout << i - j << " "; //i - j爲每次匹配的位置下標 j = nextval[strlen(t)]; //匹配成功後,j就從nextval[m]開始繼續查找 num++; //num記錄匹配的次數 } } if(flag == 1) //flag恆爲1表示沒有一次成功的匹配 { location = -1; //location爲-1表示匹配失敗 cout << "匹配失敗!"; } cout << endl; return location; //返回第一次匹配的位置下標 } int main() { int nextval[20], next[20], i, location, num = 0; /*location記錄第一次匹配的位置, num記錄匹配的次數*/ char t[20], s[20], filename[20]; //t爲子串,s爲主串,filename爲文件的名稱 cout << "請輸入文件的名稱: "; cin >> filename; read(filename, s); //從文件中讀取主串 cout << "請輸入子串: "; cin >> t; //輸入子串 while (strlen(t) > strlen(s)) //輸入錯誤,從新輸入 { cout << "輸入錯誤(子串長度大於主串長度),請從新輸入: "; cin >> t; } get_next(t, next); cout << "next數組爲: "; for (i = 0; i < strlen(t) + 1; i++) //next數組多一個元素,用來記錄子串回溯的位置 cout << next[i] << " "; get_nextval(t, nextval, next); cout << endl << "nextval數組爲: "; for (i = 0; i < strlen(t) + 1; i++) //nextval[m]即爲next[m]的值,記錄子串回溯的位置 cout << nextval[i] << " "; cout << endl; location = index_kmp(s, t, nextval, num); if (location != -1) //location不爲1表示匹配成功 { cout << "子串在主串中第一次出現的起始位置爲: " << location << endl; cout << "子串在主串中匹配的次數爲: " << num << endl; } return 0; }
(1)程序輸入:
主串s: bacbababadababacambabacaddababacasdsd
子串t: ababacaspa
程序輸出:
第一次出現的起始位置:10
匹配次數: 2 設計
(2)程序輸入:
主串s: aaaaaaaaaaaaa
子串t: aaa3d
程序輸出:
第一次出現的起始位置:0
匹配次數: 11 code
(3)程序輸入:
主串s: abcbabcbabcbabcba
子串t: abcbablog
程序輸出:
第一次出現的起始位置:0
匹配次數: 4 ci
(4)程序輸入:
主串s: abcbabcbabcbabcba
子串t: abcde
程序輸出:
匹配失敗!