20190529更新

1 增加测试用例
2 修复中文查找可能导致越界的bug
3 strstr改为不使用二分(效率会慢一些,但匹配结果相对可控),推荐使用strstrs_ext

==================================================================================

20190529:windows上建议使用strstrs_ext,linux上在数据不匹配的场景好像strstrs_normal更快一点。我把测试效率代码附上,有需要的可以自己验证。

从我自己测试的效率对比猜测,linux上gcc的strstr应该不是普通的暴力匹配法,网上的说法不正确。

==================================================================================

平时项目中有时需要用到在字符串中搜索两个或更多的关键字的情景。例如:将字符串"ab|cd#ef|"按竖线或者井号做分隔

如果是大项目,一般会采用正则表达式做处理。但有时写个小程序,不想因此引进一个正则库,所以我自己写了一个支持多关键字版本的字符串查找函数strstrs

函数说明:

  1. #include <stdio.h>
  2. #include <windows.h>
  3.  
  4. #ifndef IN
  5. #define IN
  6. #endif
  7.  
  8. //函数说明:在字符串中搜索指定的关键字,支持1-nCnt个关键字
  9. //strToFind 待查找字符串 不允许为空
  10. //strKeywords 搜索关键字字符串数组 不允许为空 数组元素不允许为空(NULL),但可以是空串("")
  11. //nCnt 关键字个数
  12. //pFound 查找到的关键字在字符串数组的位置 不允许为空
  13. //返回值:
  14. //1 如果关键字存在空串,则返回strToFind
  15. //2 如果找不到关键字则返回NULL
  16. //3 如果找到关键字,则返回关键字在strKeywords中的位置(位置从0开始)
  17.  
  18. //使用哈希加二分查找实现
  19. const char *strstrs(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
  20. //使用哈希加链接实现 推荐使用
  21. const char *strstrs_ext(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
  22. //依次查找关键字的实现
  23. const char *strstrs_normal(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
  24.  
  25. //以下是为了使用方便而增加的一些重载,没多大意义
  26. char *strstrs(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
  27. char *strstrs_ext(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
  28. char *strstrs_normal(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
  29.  
  30. char *strstrs(IN char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
  31. char *strstrs_ext(IN char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
  32. char *strstrs_normal(IN char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
  33.  
  34. const char *strstrs(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
  35. const char *strstrs_ext(const char *strToFind, const char *strKeywords[], size_t nCnt, int pFound);
  36. const char *strstrs_normal(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
  37. void tets_strstrs(int nStep); // 0 strstrs 1 strstrs_ext 2 strstrs_normal

函数实现及相应测试代码:

  1. // stdafx.cpp : source file that includes just the standard includes
  2. // sqlite_test.pch will be the pre-compiled header
  3. // stdafx.obj will contain the pre-compiled type information
  4.  
  5. #include "stdafx.h"
  6. #include <assert.h>
  7. #include <stdlib.h>
  8. #include <time.h>
  9. #include <stdio.h>
  10.  
  11. // TODO: reference any additional headers you need in STDAFX.H
  12. // and not in this file
  13.  
  14. const char *strstrs(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
  15. {
  16. return strstrs(const_cast<char *>(strToFind), strKeywords, nCnt, pFound);
  17. }
  18.  
  19. const char *strstrs_ext(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
  20. {
  21. return strstrs_ext(const_cast<char *>(strToFind), strKeywords, nCnt, pFound);
  22. }
  23.  
  24. const char *strstrs_normal(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
  25. {
  26. return strstrs_normal(const_cast<char *>(strToFind), strKeywords, nCnt, pFound);
  27. }
  28.  
  29. const char *strstrs(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
  30. {
  31. return strstrs(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
  32. }
  33.  
  34. const char *strstrs_ext(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
  35. {
  36. return strstrs_ext(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
  37. }
  38.  
  39. const char *strstrs_normal(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
  40. {
  41. return strstrs_normal(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
  42. }
  43.  
  44. char *strstrs(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
  45. {
  46. return strstrs(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
  47. }
  48.  
  49. char *strstrs_ext(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
  50. {
  51. return strstrs_ext(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
  52. }
  53.  
  54. char *strstrs_normal(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
  55. {
  56. return strstrs_normal(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
  57. }
  58.  
  59. typedef struct tagKeyPos
  60. {
  61. const char *m_str;
  62. size_t m_nIdx;
  63. size_t m_strLen;
  64. }KeyPos;
  65.  
  66. int __strstrs_cmp(const void *p1, const void *p2)
  67. {
  68. const KeyPos *pLeft = (KeyPos *)p1, *pRight = (KeyPos *)p2;
  69. int nCmp = strcmp(pLeft->m_str, pRight->m_str);
  70. if (nCmp == )
  71. {
  72. return pLeft->m_nIdx - pRight->m_nIdx;
  73. }
  74.  
  75. return nCmp;
  76. }
  77.  
  78. /*
  79. //lower_bound
  80. KeyPos *__strstrs_find_first(KeyPos *pRealBeg, KeyPos *pRealEnd, size_t *pKeyLenArr, KeyPos *pKey)
  81. {
  82. KeyPos *pBeg = pRealBeg;
  83. KeyPos *pEnd = pRealEnd;
  84.  
  85. KeyPos *pEqal = NULL;
  86. while (pBeg != pEnd)
  87. {
  88. pEqal = pBeg + (pEnd - pBeg) / 2;
  89. int nCmp = memcmp( pEqal->m_str, pKey->m_str, pEqal->m_strLen );
  90. if (nCmp == 0)
  91. {
  92. //若相等,则往前找,直至找到最后一个相等的元素
  93. while (pEqal != pBeg)
  94. {
  95. pEqal--;
  96. if (memcmp( pEqal->m_str, pKey->m_str, pEqal->m_strLen ))
  97. {
  98. return pEqal + 1;
  99. }
  100. }
  101.  
  102. return pBeg;
  103. }
  104. else if (nCmp > 0)
  105. {
  106. //中值比目标值大
  107. pEnd = pEqal;
  108. }
  109. else
  110. {
  111. //中值比目标值小
  112. pBeg = pEqal + 1;
  113. }
  114.  
  115. }
  116.  
  117. return pRealEnd;
  118. }
  119. */
  120.  
  121. KeyPos *__strstrs_find_first(KeyPos *pRealBeg, KeyPos *pRealEnd, size_t *pKeyLenArr, KeyPos *pKey)
  122. {
  123. KeyPos *pBeg = pRealBeg;
  124. KeyPos *pEnd = pRealEnd;
  125.  
  126. while (pBeg != pEnd)
  127. {
  128. int nCmp = memcmp( pBeg->m_str, pKey->m_str, pBeg->m_strLen );
  129. if (nCmp == )
  130. {
  131. return pBeg;
  132. }
  133.  
  134. ++pBeg;
  135. }
  136.  
  137. return pRealEnd;
  138. }
  139.  
  140. char *strstrs(char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
  141. {
  142. //作者:皇家救星 创建于:2016-10-19
  143. //有bug请发送邮件至89475049@qq.com 邮件主题注明:strstrs问题反馈
  144. //异常参数判断
  145. assert(strToFind != NULL);
  146. assert(strKeywords != NULL);
  147. assert(pFound != NULL);
  148. assert(nCnt > );
  149.  
  150. //记录各个关键字首字符到集合中 后面判断用
  151. bool mpFirstChar[] = {}; //这里如果用位图,可以节省不少空间
  152. for (size_t i = ; i < nCnt; i++)
  153. {
  154. //linux和win的char类型定义不一样 这里统一强制转换一下
  155. assert(strKeywords[i] != NULL);
  156. //使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
  157. mpFirstChar[(unsigned char)strKeywords[i][]] = true;
  158. if (strKeywords[i][] == '\0')
  159. {
  160. *pFound = i;
  161. return strToFind;
  162. }
  163. }
  164.  
  165. KeyPos *sortKeywords = new KeyPos[nCnt];
  166. for (size_t i = ; i < nCnt; ++i)
  167. {
  168. sortKeywords[i].m_str = strKeywords[i];
  169. sortKeywords[i].m_strLen = strlen(strKeywords[i]);
  170. sortKeywords[i].m_nIdx = i;
  171. }
  172. //不能排序,会导致关键字位置混乱
  173. //qsort(sortKeywords, nCnt, sizeof(KeyPos), __strstrs_cmp);
  174.  
  175. //使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
  176. unsigned char *p = (unsigned char *)strToFind;
  177. KeyPos key;
  178. KeyPos *pEnd = sortKeywords + nCnt;
  179. KeyPos *pResult = NULL;
  180. while (*p)
  181. {
  182. //判断当前字符是否在关键串首字符集中
  183. if (mpFirstChar[*p])
  184. {
  185. key.m_str = (char *)p;
  186. pResult = __strstrs_find_first(sortKeywords, pEnd, NULL, &key);
  187. if (pResult != pEnd)
  188. {
  189. *pFound = pResult->m_nIdx;
  190. delete []sortKeywords;
  191. return reinterpret_cast<char *>(p);
  192. }
  193. }
  194.  
  195. p++;
  196. }
  197.  
  198. delete []sortKeywords;
  199. return NULL;
  200. }
  201.  
  202. typedef struct tagKeyPosExt
  203. {
  204. size_t m_strLen;
  205. size_t m_strIdx;
  206. struct tagKeyPosExt *m_next;
  207. }KeyPosExt;
  208.  
  209. char *strstrs_ext(char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
  210. {
  211. //作者:皇家救星 创建于:2016-10-19
  212. //有bug请发送邮件至89475049@qq.com 邮件主题注明:strstrs问题反馈
  213. //20190522 修改字符串有中文会导致内存访问异常的bug
  214. //异常参数判断
  215. assert(strToFind != NULL);
  216. assert(strKeywords != NULL);
  217. assert(pFound != NULL);
  218. assert(nCnt > );
  219.  
  220. //仿内存池 减少new调用次数
  221. KeyPosExt *memPool = new KeyPosExt[nCnt]; //注意:memPool分配失败会抛异常
  222. memset(memPool, , nCnt * sizeof(KeyPosExt));
  223. int nUsed = ;
  224.  
  225. //记录各个关键字首字符到集合中 后面判断用
  226. KeyPosExt mpFirstChar[];
  227. memset(mpFirstChar, , sizeof(mpFirstChar));
  228. for (size_t i = nCnt - ; i != (size_t)-; --i)
  229. {
  230. KeyPosExt *pPos = &memPool[nUsed++];
  231. //如果同一个首字符对应多个关键字,则用链表连起来
  232. assert(strKeywords[i] != NULL);
  233. pPos->m_strIdx = i;
  234. pPos->m_strLen = strlen(strKeywords[i]);
  235.  
  236. if (pPos->m_strLen == )
  237. {
  238. *pFound = i;
  239. delete []memPool;
  240. return strToFind;
  241. }
  242.  
  243. //把新的节点插到最前面
  244. //使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
  245. KeyPosExt *pLast = &mpFirstChar[(unsigned char)strKeywords[i][]];
  246. pPos->m_next = pLast->m_next;
  247. pLast->m_next = pPos;
  248. }
  249.  
  250. //使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
  251. unsigned char *p = (unsigned char *) strToFind;
  252. while (*p)
  253. {
  254. //判断当前字符是否在关键串首字符集中
  255. for (KeyPosExt *pPos = mpFirstChar[*p].m_next; pPos != NULL; pPos = pPos->m_next)
  256. {
  257. //遍历以当前字符开头的关键串,挨个比较 看是否有匹配的
  258. if (memcmp(p, strKeywords[pPos->m_strIdx], pPos->m_strLen) == )
  259. {
  260. *pFound = pPos->m_strIdx;
  261. delete []memPool;
  262. return reinterpret_cast<char *>(p);
  263. }
  264. }
  265.  
  266. p++;
  267. }
  268.  
  269. delete []memPool;
  270. return NULL;
  271. }
  272.  
  273. char *strstrs_normal(char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
  274. {
  275. //作者:皇家救星 创建于:2016-10-19
  276. //有bug请发送邮件至89475049@qq.com 邮件主题注明:strstrs问题反馈
  277. //20190522 修改字符串有中文会导致内存访问异常的bug
  278. //异常参数判断
  279. assert(strToFind != NULL);
  280. assert(strKeywords != NULL);
  281. assert(pFound != NULL);
  282. assert(nCnt > );
  283.  
  284. char *p = NULL;
  285. for (size_t i = ; i < nCnt; i++)
  286. {
  287. assert(strKeywords[i] != NULL);
  288. if (strKeywords[i][] == '\0')
  289. {
  290. *pFound = i;
  291. return strToFind;
  292. }
  293. }
  294.  
  295. for (size_t i = ; i < nCnt; i++)
  296. {
  297. assert(strKeywords[i] != NULL);
  298. if ((p = strstr(strToFind, strKeywords[i])) != NULL)
  299. {
  300. *pFound = i;
  301. return p;
  302. }
  303. }
  304. return NULL;
  305. }
  306.  
  307. //准确性测试
  308. int tets_strstrs1()
  309. {
  310. const char *strKeywords[] = {"", "select", "union", "or", "customer", "subsid",
  311. "", "group_id", "test", "from", "truncate", "s", "english1", "", "皇家"};
  312. const char *strSqls[] = {
  313. "select * from dual",
  314. "drop table",
  315. "truncate",
  316. "english",
  317. "goodby",
  318. "get 123",
  319. "123 get",
  320. " from"
  321. "D",
  322. "s",
  323. "89sfs89",
  324. "or",
  325. "sor",
  326. "orunion",
  327. "unionor",
  328. "83eejr3r9r9r33302002013345331224312343",
  329. "去9999给",
  330. "去皇家救星给"
  331. };
  332.  
  333. for (int i = ; i < sizeof(strSqls) / sizeof(strSqls[]); ++i)
  334. {
  335. bool bFoundNormal = false;
  336. int nFoundNormal = ;
  337. if (NULL !=
  338. strstrs_normal(strSqls[i], strKeywords, sizeof(strKeywords) / sizeof(strKeywords[]), &nFoundNormal))
  339. {
  340. bFoundNormal = true;
  341. }
  342.  
  343. bool bFoundExt = false;
  344. int nFoundExt = ;
  345. if (NULL !=
  346. strstrs_ext(strSqls[i], strKeywords, sizeof(strKeywords) / sizeof(strKeywords[]), &nFoundExt))
  347. {
  348. bFoundExt = true;
  349. }
  350.  
  351. bool bFound = false;
  352. int nFound = ;
  353. if (NULL !=
  354. strstrs(strSqls[i], strKeywords, sizeof(strKeywords) / sizeof(strKeywords[]), &nFound))
  355. {
  356. bFound = true;
  357. }
  358.  
  359. if ((bFound != bFoundExt || bFound != bFoundNormal)
  360. || (nFound != nFoundExt /*|| nFound != nFoundNormal*/))
  361. {
  362. printf("error! strSqls[i] = [%s]\n", strSqls[i]);
  363. printf("bFound = %d nFound = %d\n", bFound, nFound);
  364. printf("bFoundNormal = %d nFoundNormal = %d\n", bFoundNormal, nFoundNormal);
  365. printf("bFoundExt = %d nFoundExt = %d\n", bFoundExt, nFoundExt);
  366. return - - i * ;
  367. }
  368. }
  369.  
  370. return ;
  371. }
  372.  
  373. //效率比较及准确性测试函数
  374. void tets_strstrs(int nStep)
  375. {
  376. const int max_length = ; //max_length必须大于1024
  377. const int max_keyword = ;
  378. char *strToFound = new char[max_length + ]; //待查找的字符串
  379. char *strBackup = new char[max_length + ];
  380. char *strKeywords[max_keyword]; //关键字数组
  381. const char strBase64[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
  382.  
  383. //为避免结果全是找不到关键字,随机将一个关键字复制到strToFound中
  384. //这样肯定会有找到关键字的情况,结果更有意义
  385. bool arrayFoundFlags[max_keyword] = {}; //标记是否把关键字复制到strToFound中
  386. int arrayFoundIdxs[max_keyword] = {}; //待替换的关键字(序号)
  387. int arrayFoundBeg[max_keyword] = {}; //在strToFound替换关键字的起始位置
  388.  
  389. if (tets_strstrs1() != )
  390. {
  391. printf("函数功能验证失败\n");
  392. return;
  393. }
  394.  
  395. srand((int)time(NULL));
  396. //初始化要查询的字符串
  397. for (int i = ; i < max_length; i++)
  398. {
  399. strToFound[i] = strBase64[rand() % ];
  400. }
  401. strToFound[max_length] = '\0';
  402. fprintf(stderr, "strToFound = [%s]\n", strToFound);
  403.  
  404. //初始化查询关键字
  405. for (int i = ; i < max_keyword; i++)
  406. {
  407. size_t nKeyLen = max_length / ;
  408. size_t nKeyLenMin = ;
  409. strKeywords[i] = new char[nKeyLen + ];
  410.  
  411. if (nKeyLen < nKeyLenMin)
  412. {
  413. fprintf(stderr, "max_length is too small\n");
  414. exit();
  415. }
  416. int nLen = rand() % (nKeyLen - nKeyLenMin) + nKeyLenMin;
  417. for (int j = ; j < nLen; j++)
  418. {
  419. strKeywords[i][j] = strBase64[rand() % ];
  420. }
  421. strKeywords[i][nLen] = '\0';
  422.  
  423. //为避免随机结果都是查不到的情况,这里增加一些干预
  424. //if (0 != (rand() % 10))
  425. // {
  426. // //随机抽取约9/10的关键字 复制到待查字符串中
  427. // arrayFoundFlags[i] = true;
  428. // arrayFoundIdxs[i] = rand() % (i + 1);
  429. // arrayFoundBeg[i] = 0;
  430. // }
  431.  
  432. fprintf(stderr, "strKeywords[%d] = [%s]\n", i, strKeywords[i]);
  433. fprintf(stderr, "%d: %d %d %d\n", i, arrayFoundFlags[i], arrayFoundIdxs[i], arrayFoundBeg[i]);
  434. }
  435. fflush(stderr);
  436. printf("RESULT: 函数类型 关键字总数 总耗时 总共找到次数\n");
  437. for (int cmpType = ; cmpType < ; cmpType++)
  438. {
  439. int nSn = ;
  440. double total_start = GetTickCount();
  441. for (size_t nCnt = ; nCnt < max_keyword; nCnt++)
  442. {
  443. bool bSetFound = arrayFoundFlags[nCnt];
  444. int nBeg = ;
  445. int nChange = ;
  446. int idxKeyword = ;
  447. if (bSetFound)
  448. {
  449. //把关键字替换到字符串中 这样能保证字符串肯定包含想要的字符串
  450. idxKeyword = arrayFoundIdxs[nCnt];
  451. nChange = strlen(strKeywords[idxKeyword]);
  452. nBeg = arrayFoundBeg[nCnt];
  453. memcpy(strBackup, strToFound + nBeg, nChange);
  454. strBackup[nChange] = '\0';
  455. memcpy(strToFound + nBeg, strKeywords[idxKeyword], nChange);
  456. }
  457.  
  458. double start = GetTickCount();
  459. int nFoundCnt = ;
  460.  
  461. //待查字符串从短到长
  462. for (int nStrlen = ; nStrlen < max_length; nStrlen += nStep)
  463. {
  464. //末尾要有\0 所以这里行把末尾字符备份起来 用\0覆盖 后面调用strstrs后再替换回去
  465. char cBak = strToFound[nStrlen];
  466. strToFound[nStrlen] = '\0';
  467. int nFound = -;
  468. const char *p;
  469. switch (cmpType)
  470. {
  471. case :
  472. p = strstrs(strToFound, strKeywords, nCnt + , &nFound);
  473. break;
  474. case :
  475. p = strstrs_ext(strToFound, strKeywords, nCnt + , &nFound);
  476. break;
  477. default:
  478. p = strstrs_normal(strToFound, strKeywords, nCnt + , &nFound);
  479. break;
  480. }
  481.  
  482. //fprintf(stderr, "cmpType %d %d %d\n", cmpType, nSn, nFound);
  483. nSn++;
  484. if (p != NULL)
  485. {
  486. nFoundCnt++;
  487. }
  488. else
  489. {
  490. //假设明明有把关键字拷进去但还是返回找不到,说明结果有问题
  491. if (bSetFound && ((nBeg + nChange) <= nStrlen))
  492. {
  493. printf("cmpType = %d ###############################error!\n", cmpType);
  494. printf("strToFound = [%s], nStrlen = %d, nCnt = %d\n", strToFound, nStrlen, nCnt);
  495. printf("strKeywords[arrayFoundIdxs[nCnt]] = [%s], nBeg = %d, nChange = %d\n",
  496. strKeywords[arrayFoundIdxs[nCnt]], nBeg, nChange);
  497. exit();
  498. // switch (cmpType)
  499. // {
  500. // case 0:
  501. // p = strstrs(strToFound, strKeywords, nCnt + 1, &nFound);
  502. // break;
  503. // case 1:
  504. // p = strstrs_ext(strToFound, strKeywords, nCnt + 1, &nFound);
  505. // break;
  506. // default:
  507. // p = strstrs_normal(strToFound, strKeywords, nCnt + 1, &nFound);
  508. // break;
  509. // }
  510. }
  511. }
  512.  
  513. strToFound[nStrlen] = cBak;
  514. }
  515. double end = GetTickCount();
  516. //函数类型 关键字序列 耗时 总共找到次数
  517. printf("RESULT: %d %d %f %d\n",
  518. cmpType, nCnt + , end - start, nFoundCnt);
  519. fflush(stdout);
  520. fflush(stderr);
  521.  
  522. // if (nFoundCnt == 499)
  523. // {
  524. // printf("pre strToFound = [%s], strBackup = [%s], nCnt = %d nBeg %d nChange %d idxKeyword %d strKeywords[idxKeyword] %s\n",
  525. // strToFound, strBackup, nCnt, nBeg, nChange, idxKeyword, strKeywords[idxKeyword]);
  526. // }
  527.  
  528. if (bSetFound)
  529. {
  530. memcpy(strToFound + nBeg, strBackup, nChange);
  531. }
  532. //
  533. // if (nFoundCnt == 499)
  534. // {
  535. // printf("strToFound = [%s], nCnt = %d nBeg %d nChange %d idxKeyword %d\n", strToFound, nCnt, nBeg, nChange, idxKeyword);
  536. // }
  537. }
  538.  
  539. double total_end = GetTickCount();
  540. fprintf(stderr, "总共耗时[%f]\n", total_end - total_start);
  541. }
  542.  
  543. //TODO: 此处应该要释放内存
  544. delete []strToFound;
  545. delete []strBackup;
  546. for (int i = ; i < max_keyword; i++)
  547. {
  548. delete []strKeywords[i];
  549. }
  550. }

函数效率比较图:

0 代表strstrs

1 代表strstrs_ext

2 代表strstrs_normal

可以看出,strstrs_ext比较稳定,而且效率也比较高。

在关键字列表都与查找字符串不匹配情况trstrs_normal表现好过strstrs

在关键字列表都与查找字符串基本都存在匹配项情况strstrs表现好过strs_normal

在任何情况下strstrs_ext都表现 最好

一个在字符串中查找多个关键字的函数strstrs(三种不同算法实现及效率分析)的更多相关文章

  1. 网络中,FIFO、LRU、OPT这三种置换算法的缺页次数

    FIFO.LRU.OPT这三种置换算法的缺页次数 转载  由于要考计算机四级网络,这里遇到了问题,就搜了一些资料来解疑. 考虑下述页面走向: 1,2,3,4,2,1,5,6,2,1,2,3,7,6,3 ...

  2. C++中三种传递参数方法的效率分析

    众所周知,在C++中有三种参数传递的方式: 按值传递(pass by value) #include <iostream> using namespace std; void swap(i ...

  3. js实现从字符串中查找出现次数最多的字符的两种解决办法

    方法一:正则表达式匹配 var str = "adadfdfseffserfefsefseeffffftsdg"; ; var result = ""; whi ...

  4. 1.3 正则表达式和Python语言-1.3.5使用 search()在一个字符串中查找模式(搜索与匹配 的对比)

    1.3.5 使用 search()在一个字符串中查找模式(搜索与匹配的对比) 其实,想要搜索的模式出现在一个字符串中间部分的概率,远大于出现在字符串起始部分的概率.这也就是 search()派上用场的 ...

  5. hiho1482出勤记录II(string类字符串中查找字符串,库函数的应用)

    string类中有很多好用的函数,这里介绍在string类字符串中查找字符串的函数. string类字符串中查找字符串一般可以用: 1.s.find(s1)函数,从前往后查找与目标字符串匹配的第一个位 ...

  6. Excel-判断一个文本字符串中是否包含数字! 判断一个文本字符串是否是纯汉字!

    0.判断一个文本字符串中是否包含数字!/判断一个文本字符串是否是纯汉字! 公式=IF(LENB(A1)=2*LEN(A1),"都是汉字","含有非汉字字符") ...

  7. ARM微处理器中支持字节、半字、字三种数据类型,地址的低两位为0是啥意思?

    问题: ARM微处理器中支持字节.半字.字三种数据类型,其中,字需要4字节对齐(地址的低两位为0).半字需要2字节对齐(地址的最低位为0).我想问的是括号中的内容是什么意思呢?请牛人帮忙解释一下!谢谢 ...

  8. PAT 10-1 在字符串中查找指定字符

    百度了一下另外两位同学的做法,都是先判断是否匹配,然后再用一个for()循环输出,我当然也是先判断,然后,就直接puts(),还是巧妙一点,题设要求及代码实现如下 /* Name: Copyright ...

  9. [LeetCode] Find And Replace in String 在字符串中查找和替换

    To some string S, we will perform some replacement operations that replace groups of letters with ne ...

随机推荐

  1. uva 11324 The Largest Clique (Tarjan+记忆化)

    /*每个环 要么不选 要么全选 可缩点 就得到一个GAD图 然后搞搞算出最大路径*/ #include<iostream> #include<cstdio> #include& ...

  2. 面试题——分析从输入url到页面返回的过程(或者查询返回过程)

    1. You enter a URL into the browser(输入一个url地址) 2.The browser looks up the IP address for the domain ...

  3. DEDECMS批量修改默认文章和列表命名规则的方法

    很多人因为添加分类而苦恼,尤其是批量添加的时候,必须要重新修改一下文章命名规则和列表命名规则,都是为了做SEO.如果进行默认值的修改,就会事半功倍.不多说. 一.DEDE5.5修改默认文章命名规则. ...

  4. JS 改变input 输入框样式

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  5. 开源的Android开发框架-------PowerFramework使用心得(一)总体介绍

    PowerFramework是一款几乎囊括了所有Android基础功能的框架应用,这个框架目前是开源的,开发者可以在这个框架的基础上进行二次开发.结合开发者自己的UI设计,可以很快就能开发出具备基础应 ...

  6. Objective-C学习篇04—多态

    多态 多态的概念 有这样一个例子.早上我和同事说口渴了.结果:A同事拿着我的水杯去给我接了一杯水.B同事顺手在饮水机上拿了一次性纸杯给我接了杯水.C同事给了我一瓶他早上刚买的饮料.同事们得到的是同样的 ...

  7. ubuntu下安装Vmare Workstation,并安装mac补丁

    最近想学习一下关于ios方面的开发,但是苦于自己的电脑已经装了两个系统:一个win7,一个ubuntu.两系统均装在物理硬盘上,不想格盘,所以装个虚拟机玩玩.决定使用Vmare Workstation ...

  8. 【USACO 3.3.2】商品购物

    [描述] 在商店中,每一种商品都有一个价格(用整数表示).例如,一朵花的价格是 2 zorkmids (z),而一个花瓶的价格是 5z .为了吸引更多的顾客,商店举行了促销活动. 促销活动把一个或多个 ...

  9. Eclipse代码注释模板修改

    /** * @ClassName: ${type_name} * @author: <font color="red"><b>ZF</b>< ...

  10. Jquery的外部链接和编写样式

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></ ...