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. urlwrite伪静态(SAE、PHP、JSP)

    在SAE里,直接配置config.yaml文件,文件可以配置的内容包含: 目录默认页面 自定义错误页面 压缩 页面重定向 页面过期 设置响应Header的Content-Type appname: x ...

  2. java编程思想-注解思维导图

  3. ASP.NET5 静态文件

    静态文件,包括HTML文件,CSS文件,图像文件和JavaScript文件,它是一个应用里所包含的资源. 1. 提供静态文件 默认的,静态文件存储在你的webroot目录下面,webroot的路径定义 ...

  4. Ext4.1 Grid 分页查询

    转载:http://blog.csdn.net/zyujie/article/details/16362747 最近用Ext4.1自己做了做项目的练习:把一些知识点,在这里记录下来了! 上面一个for ...

  5. 本地代码上传 -> Github

    首先在控制台cd到你的本地项目,这里以teat为例 1.执行命令:  git init 2.将项目文件添加到仓库中:  git add . (可以是指定文件,将“.”转换为指定文件) 3.接下来com ...

  6. [置顶] Spring的DI依赖实现分析

    DI(依赖注入)是Spring最底层的核心容器要实现的功能之一,利用DI可以实现程序功能的控制反转(控制反转即程序之间之间的依赖关系不再由程序员来负责,而是由Spring容器来负责) 一个简单的例子( ...

  7. jQuery中事件的学习

    刚学习了jQuery中的事件,主要通过bind(),toggle(),hover()来主要实现,下面先说一说关于bind的想关要点. 1.bind方法. bind方法的主要参数为bind(type,f ...

  8. $().change事件

    change([[data],fn]) 当元素的value值发生改变时发生change事件 适用于: 文本域 text textarea和select元素 text textarea 元素失去焦点时发 ...

  9. rename 后缀

    for file in $(find . -name "*.del" -type f);do mv "$file" "${file%.del}&quo ...

  10. USACO1.5 Checker Challenge(类n皇后问题)

    B - B Time Limit:1000MS     Memory Limit:16000KB     64bit IO Format:%lld & %llu   Description E ...