//大规模字符串近似匹配程序//程序操作描述:用户首先输入需要放入库中的文本串个数(整数),然后逐一输入放入的各个文本串,然后输入需要进行近似匹配的模式串
//  程序将从文本串库中找出近似度K最高的模式串输出并输出近似度K,接着将输出具体如果将该文本串修改为与模式串相同的详细最优操作序列
//程序使用算法类型:动态规划法(求近似度K)、回溯法(求最近似文本串)、减治法(求化归操作序列)#include<iostream>//使用iostream头文件用于输入输出
#include<ctime>//使用ctime头文件用于计时
#include<cmath>//使用cmath头文件,用其中的绝对值函数参与运算
#include<stack>//使用stack头文件,用于使用其中的栈适配器来完成修改操作序列倒退的反向输出
#include<string>//使用string头文件,用于处理本程序中各处使用的string类的相关处理
using namespace std;//用于求三个整数中的最小值的函数,采用内联形式和常引用传参,保证了函数效率和参数的安全性
inline int Get_Min(const int& a, const int& b, const int& c)
{if (a <= b && a <= c)return a;else if (b <= a && b <= c)return b;else return c;
}//用于对给定的模式串求出近似程度最高的文本串的函数,是本次课程设计的主要函数,采用常引用传参提高效率
void Most_Approximate_String(const string* Texts, const int* Lengths, const unsigned& number, const string& Model,const int& Max_TextLength)
{clock_t start = clock();//记录函数的开始时间int Model_Length = Model.length();//记录模式串的长度int Min_K(Model_Length);//以模式串的长度作为局部最优解进行回溯查找(此处用到了回溯法,避免了蛮力法的逐一尝试)int Most_Approximate_Position(0);//记录局部最优近似匹配文本串的下标int** Matrix (new int* [Model_Length + 1]);//用一个二维整型数组来作为动态规划矩阵for (int i = 0; i <= Model_Length; ++i){Matrix[i] = new int[Max_TextLength + 1];//对矩阵的每行进行初始化,长度为最长的文本串的长度,这样可以避免重复定义矩阵,节约了空间并提高效率}for (int row = 0; row <= Model_Length; ++row)//对矩阵的首列进行初始化{Matrix[row][0] = row;}for (int col = 0; col <= Max_TextLength; ++col)//对矩阵的首行进行初始化{Matrix[0][col] = col;}//按照顺序取出库中的每一个文本串进行下面操作,通过回溯法文本串的长度进行回溯,减小遍历工作量for (unsigned pos = 0; pos < number; ++pos){int Length_Dif = Texts[pos].length() - Model_Length;//由于两个串的近似度K一定大于等于长度之差的绝对值,因此如果一个文本串与模式串相比过长或过短,则可以忽略此次比较,提高效率if (abs(Length_Dif) >= Min_K)continue;else{//填表操作,也就是按照动态规划思想,求出该文本串对应的矩阵中各个元素的值for (int row = 1; row <= Model_Length; ++row){for (int col = 1; col <= Lengths[pos]; ++col){//第一种情况:文本串与模式串在该位置的字符相同if (Model[row - 1] == Texts[pos][col - 1]){Matrix[row][col] = Get_Min(Matrix[row - 1][col - 1], Matrix[row - 1][col] + 1, Matrix[row][col - 1] + 1);}//第二种情况:文本串与模式串在该位置的字符不同,也就是需要进行三种修改操作中的一种else{Matrix[row][col] = Get_Min(Matrix[row - 1][col - 1], Matrix[row][col - 1], Matrix[row - 1][col]) + 1;}}}//每次循环完一次,即考虑是否需要更新局部最优解if (Matrix[Model_Length][Lengths[pos]] < Min_K){Min_K = Matrix[Model_Length][Lengths[pos]];Most_Approximate_Position = pos;//更新局部最优解的同时记录该文本串在库中的下标}}}cout << "库中近似度最高的文本串为:" << Texts[Most_Approximate_Position] << " ,近似度K值为:" << Min_K << endl;//输出最近似的文本串和近似度Kcout << endl;//上述操作找到了近似度最高的文本串,下面来求出对于该文本串的最优修改序列,使得其能够完全与模式串相同string Text_On_Pos = Texts[Most_Approximate_Position];//根据上面记录的下标从文本串库中取出最优匹配串int Length_On_Pos = Lengths[Most_Approximate_Position];//根据上面记录的下标记录最优匹配串的长度//继续沿用之前定义的矩阵来求出该文本串对应的动态规划矩阵,由于方法与上面相同因此不过多解释for (int row = 1; row <= Model_Length; ++row){for (int col = 1; col <= Length_On_Pos; ++col){if (Model[row - 1] == Text_On_Pos[col - 1]){Matrix[row][col] = Get_Min(Matrix[row - 1][col] - 1, Matrix[row][col - 1], Matrix[row - 1][col] + 1);}else{Matrix[row][col] = Get_Min(Matrix[row - 1][col - 1], Matrix[row][col - 1], Matrix[row - 1][col]) + 1;}}}//通过倒推的方法求出操作序列int step = Min_K;stack<string> Modify_Operations;//考虑到倒推法的操作顺序与输出顺序相反,因此使用栈这种先进后出的数据结构string operation;//记录每一步操作//从矩阵的最右下角开始(最右下角的元素就是最优解K),倒推走回起点for (int row = Model_Length, col = Length_On_Pos; step >= 1 && row >= 1 && col >= 1;){int Left_Up = Matrix[row-1][col-1];//记录当前元素左上角的元素的值int Left = Matrix[row][col - 1];//记录当前元素左边的元素的值int Up = Matrix[row - 1][col];//记录当前元素上方的元素的值if (Left_Up <= Left && Left_Up <= Up)//第一种情况:左上角的元素为三者中最小(或最小之一),则从当前位置走向左上角{if (Matrix[row][col] == Matrix[row - 1][col - 1] + 1)//如果当前位置元素和左上角位置元素刚好相差1,说明此处发生了字符修改,记录修改内容{operation = "第" + to_string(step) + "步修改为:将文本串中下标为" +to_string (col - 1) + "的字符" + Text_On_Pos[col-1]\+ "修改为模式串中下标为" +to_string(row - 1) + "的字符" + Model[row - 1];step--;Modify_Operations.push(operation);}row--;col--;}else if (Left <= Left_Up && Left <= Up)//第二种情况:左边的元素为三者中最小,则从当前位置走向左边{if (Matrix[row][col] == Matrix[row][col - 1] + 1)//如果当前位置元素和左边位置元素刚好相差1,说明此处发生了字符删除,记录修改内容{operation = "第" + to_string(step) + "步修改为:将文本串中下标为" + to_string(col - 1) + "的字符" + Text_On_Pos[col - 1] + "删除";step--;Modify_Operations.push(operation);}col--;}else//第三种情况:上方的元素为三者中最小,则从当前位置走到上方{if (Matrix[row][col] == Matrix[row - 1][col] + 1)//如果当前位置元素和上方位置元素刚好相差1,说明此处发生了字符添加,记录修改内容{operation = "第" + to_string(step) + "步修改为:在文本串中下标为" + to_string(col - 1) + "处添加模式串中下标为" \+ to_string(row - 1) + "的元素" + Model[row - 1];step--;Modify_Operations.push(operation);}row--;}}if (Modify_Operations.empty())//如果栈本身为空,说明两个字符串完全相同,无需修改{cout << "由于两处的字符串完全相同,因此无需修改!" << endl;}else//如果两个字符串不同,则从操作栈中逐一取出表示操作序列的字符串并进行输出{cout << "使用的最优修改策略如下:" << endl;while (!Modify_Operations.empty()){operation = Modify_Operations.top();cout << operation << endl;Modify_Operations.pop();}}clock_t end = clock();//记录程序终止时间cout << "程序结束" << endl;cout << "本次的查找修改时间为:" << double(end - start) / CLK_TCK << "ms" << endl;//输出计算K值和输出操作序列的时间delete[]Matrix;//最后当然要删除矩阵归还内存空间
}int main(void)
{unsigned TextString_Num;//用一个无符号整型变量记录需要放入库中的文本串个数cout << "请输入需要放入库中的文本串的个数:";cin >> TextString_Num;string* Text_Strings (new string[TextString_Num]);//用一个堆数组存储库中的所有文本串(之所以不使用更加方便的向量容器vector是因为其效率远低于数组)int* Texts_Length (new int[TextString_Num]);//用一个堆数组存储库中所有文本串的长度用于回溯(不使用向量的原因同上)int Max_Length = 0;//用一个整型变量记录所有文本串的最大长度,这样可以仅仅通过一个矩阵来完成后续运算,节约了大量空间cout << "请分别输入这些字符串:" << endl;for (unsigned i = 0; i < TextString_Num; ++i){cin >> Text_Strings[i];Texts_Length[i] = Text_Strings[i].length();//记录每一个字符串的长度if (Texts_Length[i] > Max_Length)//如果遍历到某处时该字符串的长度长于当前最大字符串长度,则更新当前最大字符串长度{Max_Length = Texts_Length[i];}}string Model_String;//定义模式串cout << "请输入需要进行近似匹配的模式串:";cin >> Model_String;cout << endl;Most_Approximate_String(Text_Strings, Texts_Length, TextString_Num, Model_String,Max_Length);//使用求最优近似串的函数进行求解//最后需要注意归还所占用的内存空间(怎么能为了提高效率就不做这件事情呢)delete[]Text_Strings;delete[] Texts_Length;return 0;
}

大规模字符串的近似匹配问题(带详细注释的C++实现)相关推荐

  1. android小游戏源码拼图,android编写的数字拼图游戏(带详细注释)

    [实例简介]自己正在学android,编写了一个简单的数字拼图游戏,有详细注释,适合初学者参考使用,比较简单易懂 [实例截图] [核心代码] package com.tsu; import java. ...

  2. java key锁 实现对某个key(字符串)加同步锁 带详细注释

    相信大家都用过Redis分布式锁吧 Redis分布式锁是对某个字符串来进行上锁的 用起来嘎嘎爽 于是我就想能不能自己实现一个根据key来同步的锁?下面为该锁的实现过程 若有线程安全问题或者是讲解不到位 ...

  3. 转-- iOS 30多个iOS常用动画,带详细注释

    // // CoreAnimationEffect.h // CoreAnimationEffect // // Created by VincentXue on 13-1-19. // Copyri ...

  4. OpenCV下的灰度直方图生成及显示的源码,带详细注释

    图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 注:本文的源码来自博客  http://blog ...

  5. c语言括号匹配输出个数字,C程序括号匹配检查(带详细注释)

    编写一程序检查C源程序文件中{}.()等括号是否匹配,并输出第一个检测到的不匹配的括号及所对应括号所在的行号(程序中只有一个括号不匹配). 注意: 1.     除了括号可能不匹配外,输入的C源程序无 ...

  6. 【Java】Java实现贪吃蛇小游戏(带详细注释)

    源码 源码来源:Java swing 写的贪吃蛇代码200行 前段时间在博客上看到了这段源码,由于自己没有用Java做过小游戏,于是就copy了一下,然后在自己电脑上运行,顺便加上了注释. 代码 gr ...

  7. C程序括号匹配检查(带详细注释)

    编写一程序检查C源程序文件中{}.()等括号是否匹配,并输出第一个检测到的不匹配的括号及所对应括号所在的行号(程序中只有一个括号不匹配). 注意: 1.     除了括号可能不匹配外,输入的C源程序无 ...

  8. python 抖音评论_新手python抖音无水印解析带详细注释

    资源来源网络,如果需要授权,请大家更换源码,模块仅供学习,如需商用请购买正版授权,本栏目不提供技术服务,积分不够请签到,或者会员中心投稿源码 注释都很详细,可以看看注释!友情提醒,仅供学习使用,请勿用 ...

  9. 基于OpenCV实现的图像油画效果代码(高效率、低耗时的C++代码-带详细注释)

    油画的特点是其颜色值很有限,并且笔比较粗,所以我们要实现油画效果关键就是利用运算实现这两点. 本文实现的图像油画效果代码原理如下: 一.将原图进行灰度化处理后将灰度值线性压缩到0~level,得到图像 ...

最新文章

  1. Linux中的动态库和静态库(.a/.la/.so/.o)
  2. struts2 中 Preparable 接口实现数据准备
  3. appcompat_v7\res\values-v21\themes_base.xml:158: error: Error: No resource
  4. 《3D数学基础系列视频》1.1向量基本概念
  5. MySQL出现Waiting for table metadata lock的原因以及解决方法
  6. 为什么你的应用程序需要崩溃
  7. vscode可以打开jupyternotebook吗_刚刚,官方宣布 VS Code 支持 Python 全开发了!
  8. 条件、循环、函数定义 练习
  9. QMap与QHash
  10. 华为手机如何固定横屏_华为手机如何录屏?原来方法这么简单,手把手教你学会...
  11. IBM与红帽联手构建开源混合云环境
  12. three.js 来源目光(十三)Math/Ray.js
  13. 贝叶斯公式的图形记忆
  14. 一、绘制不同类别特征均值标准差直方图
  15. 倍福PLC——ADS上位机通讯
  16. H.323 and Associated Protocols
  17. Homa: A Receiver-Driven Low-Latency Transport Protocol Using Network Priorities(Sigcomm'18) 论文记录
  18. 超详细的KNIME安装教程!
  19. Android 短信验证 SDK 接入(Mob SMSSDK)
  20. 2面之后说等HR通知,等不到怎么办

热门文章

  1. Google Code Jam 2014 -- C
  2. 流动比率liquidity rate解释
  3. EventBus如何使用及一些常见场景
  4. DM8达梦数据库安装及卸载方法
  5. 为大家介绍一下自制DIY面膜的好地方
  6. 静态网站生成器Gridsome
  7. C语言square的用法,square的用法总结大全
  8. 个人中心滚动标题渐变颜色
  9. Word让目录页码和正文页码独立分开计算,分隔符中分页符、“下一页”分节符的区别与使用选择
  10. es模糊查询与精准查询混用、距离排序、返回距离