一个在字符串中查找多个关键字的函数strstrs(三种不同算法实现及效率分析)
20190529更新
1 增加测试用例
2 修复中文查找可能导致越界的bug
3 strstr改为不使用二分(效率会慢一些,但匹配结果相对可控),推荐使用strstrs_ext
==================================================================================
20190529:windows上建议使用strstrs_ext,linux上在数据不匹配的场景好像strstrs_normal更快一点。我把测试效率代码附上,有需要的可以自己验证。
从我自己测试的效率对比猜测,linux上gcc的strstr应该不是普通的暴力匹配法,网上的说法不正确。
==================================================================================
平时项目中有时需要用到在字符串中搜索两个或更多的关键字的情景。例如:将字符串"ab|cd#ef|"按竖线或者井号做分隔
如果是大项目,一般会采用正则表达式做处理。但有时写个小程序,不想因此引进一个正则库,所以我自己写了一个支持多关键字版本的字符串查找函数strstrs
函数说明:
#include <stdio.h>
#include <windows.h> #ifndef IN
#define IN
#endif //函数说明:在字符串中搜索指定的关键字,支持1-nCnt个关键字
//strToFind 待查找字符串 不允许为空
//strKeywords 搜索关键字字符串数组 不允许为空 数组元素不允许为空(NULL),但可以是空串("")
//nCnt 关键字个数
//pFound 查找到的关键字在字符串数组的位置 不允许为空
//返回值:
//1 如果关键字存在空串,则返回strToFind
//2 如果找不到关键字则返回NULL
//3 如果找到关键字,则返回关键字在strKeywords中的位置(位置从0开始) //使用哈希加二分查找实现
const char *strstrs(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
//使用哈希加链接实现 推荐使用
const char *strstrs_ext(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
//依次查找关键字的实现
const char *strstrs_normal(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound); //以下是为了使用方便而增加的一些重载,没多大意义
char *strstrs(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
char *strstrs_ext(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
char *strstrs_normal(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound); char *strstrs(IN char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
char *strstrs_ext(IN char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
char *strstrs_normal(IN char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound); const char *strstrs(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
const char *strstrs_ext(const char *strToFind, const char *strKeywords[], size_t nCnt, int pFound);
const char *strstrs_normal(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
void tets_strstrs(int nStep); // 0 strstrs 1 strstrs_ext 2 strstrs_normal
函数实现及相应测试代码:
// stdafx.cpp : source file that includes just the standard includes
// sqlite_test.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information #include "stdafx.h"
#include <assert.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h> // TODO: reference any additional headers you need in STDAFX.H
// and not in this file const char *strstrs(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs(const_cast<char *>(strToFind), strKeywords, nCnt, pFound);
} const char *strstrs_ext(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_ext(const_cast<char *>(strToFind), strKeywords, nCnt, pFound);
} const char *strstrs_normal(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_normal(const_cast<char *>(strToFind), strKeywords, nCnt, pFound);
} const char *strstrs(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} const char *strstrs_ext(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_ext(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} const char *strstrs_normal(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_normal(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} char *strstrs(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} char *strstrs_ext(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_ext(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} char *strstrs_normal(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_normal(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} typedef struct tagKeyPos
{
const char *m_str;
size_t m_nIdx;
size_t m_strLen;
}KeyPos; int __strstrs_cmp(const void *p1, const void *p2)
{
const KeyPos *pLeft = (KeyPos *)p1, *pRight = (KeyPos *)p2;
int nCmp = strcmp(pLeft->m_str, pRight->m_str);
if (nCmp == )
{
return pLeft->m_nIdx - pRight->m_nIdx;
} return nCmp;
} /*
//lower_bound
KeyPos *__strstrs_find_first(KeyPos *pRealBeg, KeyPos *pRealEnd, size_t *pKeyLenArr, KeyPos *pKey)
{
KeyPos *pBeg = pRealBeg;
KeyPos *pEnd = pRealEnd; KeyPos *pEqal = NULL;
while (pBeg != pEnd)
{
pEqal = pBeg + (pEnd - pBeg) / 2;
int nCmp = memcmp( pEqal->m_str, pKey->m_str, pEqal->m_strLen );
if (nCmp == 0)
{
//若相等,则往前找,直至找到最后一个相等的元素
while (pEqal != pBeg)
{
pEqal--;
if (memcmp( pEqal->m_str, pKey->m_str, pEqal->m_strLen ))
{
return pEqal + 1;
}
} return pBeg;
}
else if (nCmp > 0)
{
//中值比目标值大
pEnd = pEqal;
}
else
{
//中值比目标值小
pBeg = pEqal + 1;
} } return pRealEnd;
}
*/ KeyPos *__strstrs_find_first(KeyPos *pRealBeg, KeyPos *pRealEnd, size_t *pKeyLenArr, KeyPos *pKey)
{
KeyPos *pBeg = pRealBeg;
KeyPos *pEnd = pRealEnd; while (pBeg != pEnd)
{
int nCmp = memcmp( pBeg->m_str, pKey->m_str, pBeg->m_strLen );
if (nCmp == )
{
return pBeg;
} ++pBeg;
} return pRealEnd;
} char *strstrs(char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
//作者:皇家救星 创建于:2016-10-19
//有bug请发送邮件至89475049@qq.com 邮件主题注明:strstrs问题反馈
//异常参数判断
assert(strToFind != NULL);
assert(strKeywords != NULL);
assert(pFound != NULL);
assert(nCnt > ); //记录各个关键字首字符到集合中 后面判断用
bool mpFirstChar[] = {}; //这里如果用位图,可以节省不少空间
for (size_t i = ; i < nCnt; i++)
{
//linux和win的char类型定义不一样 这里统一强制转换一下
assert(strKeywords[i] != NULL);
//使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
mpFirstChar[(unsigned char)strKeywords[i][]] = true;
if (strKeywords[i][] == '\0')
{
*pFound = i;
return strToFind;
}
} KeyPos *sortKeywords = new KeyPos[nCnt];
for (size_t i = ; i < nCnt; ++i)
{
sortKeywords[i].m_str = strKeywords[i];
sortKeywords[i].m_strLen = strlen(strKeywords[i]);
sortKeywords[i].m_nIdx = i;
}
//不能排序,会导致关键字位置混乱
//qsort(sortKeywords, nCnt, sizeof(KeyPos), __strstrs_cmp); //使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
unsigned char *p = (unsigned char *)strToFind;
KeyPos key;
KeyPos *pEnd = sortKeywords + nCnt;
KeyPos *pResult = NULL;
while (*p)
{
//判断当前字符是否在关键串首字符集中
if (mpFirstChar[*p])
{
key.m_str = (char *)p;
pResult = __strstrs_find_first(sortKeywords, pEnd, NULL, &key);
if (pResult != pEnd)
{
*pFound = pResult->m_nIdx;
delete []sortKeywords;
return reinterpret_cast<char *>(p);
}
} p++;
} delete []sortKeywords;
return NULL;
} typedef struct tagKeyPosExt
{
size_t m_strLen;
size_t m_strIdx;
struct tagKeyPosExt *m_next;
}KeyPosExt; char *strstrs_ext(char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
//作者:皇家救星 创建于:2016-10-19
//有bug请发送邮件至89475049@qq.com 邮件主题注明:strstrs问题反馈
//20190522 修改字符串有中文会导致内存访问异常的bug
//异常参数判断
assert(strToFind != NULL);
assert(strKeywords != NULL);
assert(pFound != NULL);
assert(nCnt > ); //仿内存池 减少new调用次数
KeyPosExt *memPool = new KeyPosExt[nCnt]; //注意:memPool分配失败会抛异常
memset(memPool, , nCnt * sizeof(KeyPosExt));
int nUsed = ; //记录各个关键字首字符到集合中 后面判断用
KeyPosExt mpFirstChar[];
memset(mpFirstChar, , sizeof(mpFirstChar));
for (size_t i = nCnt - ; i != (size_t)-; --i)
{
KeyPosExt *pPos = &memPool[nUsed++];
//如果同一个首字符对应多个关键字,则用链表连起来
assert(strKeywords[i] != NULL);
pPos->m_strIdx = i;
pPos->m_strLen = strlen(strKeywords[i]); if (pPos->m_strLen == )
{
*pFound = i;
delete []memPool;
return strToFind;
} //把新的节点插到最前面
//使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
KeyPosExt *pLast = &mpFirstChar[(unsigned char)strKeywords[i][]];
pPos->m_next = pLast->m_next;
pLast->m_next = pPos;
} //使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
unsigned char *p = (unsigned char *) strToFind;
while (*p)
{
//判断当前字符是否在关键串首字符集中
for (KeyPosExt *pPos = mpFirstChar[*p].m_next; pPos != NULL; pPos = pPos->m_next)
{
//遍历以当前字符开头的关键串,挨个比较 看是否有匹配的
if (memcmp(p, strKeywords[pPos->m_strIdx], pPos->m_strLen) == )
{
*pFound = pPos->m_strIdx;
delete []memPool;
return reinterpret_cast<char *>(p);
}
} p++;
} delete []memPool;
return NULL;
} char *strstrs_normal(char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
//作者:皇家救星 创建于:2016-10-19
//有bug请发送邮件至89475049@qq.com 邮件主题注明:strstrs问题反馈
//20190522 修改字符串有中文会导致内存访问异常的bug
//异常参数判断
assert(strToFind != NULL);
assert(strKeywords != NULL);
assert(pFound != NULL);
assert(nCnt > ); char *p = NULL;
for (size_t i = ; i < nCnt; i++)
{
assert(strKeywords[i] != NULL);
if (strKeywords[i][] == '\0')
{
*pFound = i;
return strToFind;
}
} for (size_t i = ; i < nCnt; i++)
{
assert(strKeywords[i] != NULL);
if ((p = strstr(strToFind, strKeywords[i])) != NULL)
{
*pFound = i;
return p;
}
}
return NULL;
} //准确性测试
int tets_strstrs1()
{
const char *strKeywords[] = {"", "select", "union", "or", "customer", "subsid",
"", "group_id", "test", "from", "truncate", "s", "english1", "", "皇家"};
const char *strSqls[] = {
"select * from dual",
"drop table",
"truncate",
"english",
"goodby",
"get 123",
"123 get",
" from"
"D",
"s",
"89sfs89",
"or",
"sor",
"orunion",
"unionor",
"83eejr3r9r9r33302002013345331224312343",
"去9999给",
"去皇家救星给"
}; for (int i = ; i < sizeof(strSqls) / sizeof(strSqls[]); ++i)
{
bool bFoundNormal = false;
int nFoundNormal = ;
if (NULL !=
strstrs_normal(strSqls[i], strKeywords, sizeof(strKeywords) / sizeof(strKeywords[]), &nFoundNormal))
{
bFoundNormal = true;
} bool bFoundExt = false;
int nFoundExt = ;
if (NULL !=
strstrs_ext(strSqls[i], strKeywords, sizeof(strKeywords) / sizeof(strKeywords[]), &nFoundExt))
{
bFoundExt = true;
} bool bFound = false;
int nFound = ;
if (NULL !=
strstrs(strSqls[i], strKeywords, sizeof(strKeywords) / sizeof(strKeywords[]), &nFound))
{
bFound = true;
} if ((bFound != bFoundExt || bFound != bFoundNormal)
|| (nFound != nFoundExt /*|| nFound != nFoundNormal*/))
{
printf("error! strSqls[i] = [%s]\n", strSqls[i]);
printf("bFound = %d nFound = %d\n", bFound, nFound);
printf("bFoundNormal = %d nFoundNormal = %d\n", bFoundNormal, nFoundNormal);
printf("bFoundExt = %d nFoundExt = %d\n", bFoundExt, nFoundExt);
return - - i * ;
}
} return ;
} //效率比较及准确性测试函数
void tets_strstrs(int nStep)
{
const int max_length = ; //max_length必须大于1024
const int max_keyword = ;
char *strToFound = new char[max_length + ]; //待查找的字符串
char *strBackup = new char[max_length + ];
char *strKeywords[max_keyword]; //关键字数组
const char strBase64[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"}; //为避免结果全是找不到关键字,随机将一个关键字复制到strToFound中
//这样肯定会有找到关键字的情况,结果更有意义
bool arrayFoundFlags[max_keyword] = {}; //标记是否把关键字复制到strToFound中
int arrayFoundIdxs[max_keyword] = {}; //待替换的关键字(序号)
int arrayFoundBeg[max_keyword] = {}; //在strToFound替换关键字的起始位置 if (tets_strstrs1() != )
{
printf("函数功能验证失败\n");
return;
} srand((int)time(NULL));
//初始化要查询的字符串
for (int i = ; i < max_length; i++)
{
strToFound[i] = strBase64[rand() % ];
}
strToFound[max_length] = '\0';
fprintf(stderr, "strToFound = [%s]\n", strToFound); //初始化查询关键字
for (int i = ; i < max_keyword; i++)
{
size_t nKeyLen = max_length / ;
size_t nKeyLenMin = ;
strKeywords[i] = new char[nKeyLen + ]; if (nKeyLen < nKeyLenMin)
{
fprintf(stderr, "max_length is too small\n");
exit();
}
int nLen = rand() % (nKeyLen - nKeyLenMin) + nKeyLenMin;
for (int j = ; j < nLen; j++)
{
strKeywords[i][j] = strBase64[rand() % ];
}
strKeywords[i][nLen] = '\0'; //为避免随机结果都是查不到的情况,这里增加一些干预
//if (0 != (rand() % 10))
// {
// //随机抽取约9/10的关键字 复制到待查字符串中
// arrayFoundFlags[i] = true;
// arrayFoundIdxs[i] = rand() % (i + 1);
// arrayFoundBeg[i] = 0;
// } fprintf(stderr, "strKeywords[%d] = [%s]\n", i, strKeywords[i]);
fprintf(stderr, "%d: %d %d %d\n", i, arrayFoundFlags[i], arrayFoundIdxs[i], arrayFoundBeg[i]);
}
fflush(stderr);
printf("RESULT: 函数类型 关键字总数 总耗时 总共找到次数\n");
for (int cmpType = ; cmpType < ; cmpType++)
{
int nSn = ;
double total_start = GetTickCount();
for (size_t nCnt = ; nCnt < max_keyword; nCnt++)
{
bool bSetFound = arrayFoundFlags[nCnt];
int nBeg = ;
int nChange = ;
int idxKeyword = ;
if (bSetFound)
{
//把关键字替换到字符串中 这样能保证字符串肯定包含想要的字符串
idxKeyword = arrayFoundIdxs[nCnt];
nChange = strlen(strKeywords[idxKeyword]);
nBeg = arrayFoundBeg[nCnt];
memcpy(strBackup, strToFound + nBeg, nChange);
strBackup[nChange] = '\0';
memcpy(strToFound + nBeg, strKeywords[idxKeyword], nChange);
} double start = GetTickCount();
int nFoundCnt = ; //待查字符串从短到长
for (int nStrlen = ; nStrlen < max_length; nStrlen += nStep)
{
//末尾要有\0 所以这里行把末尾字符备份起来 用\0覆盖 后面调用strstrs后再替换回去
char cBak = strToFound[nStrlen];
strToFound[nStrlen] = '\0';
int nFound = -;
const char *p;
switch (cmpType)
{
case :
p = strstrs(strToFound, strKeywords, nCnt + , &nFound);
break;
case :
p = strstrs_ext(strToFound, strKeywords, nCnt + , &nFound);
break;
default:
p = strstrs_normal(strToFound, strKeywords, nCnt + , &nFound);
break;
} //fprintf(stderr, "cmpType %d %d %d\n", cmpType, nSn, nFound);
nSn++;
if (p != NULL)
{
nFoundCnt++;
}
else
{
//假设明明有把关键字拷进去但还是返回找不到,说明结果有问题
if (bSetFound && ((nBeg + nChange) <= nStrlen))
{
printf("cmpType = %d ###############################error!\n", cmpType);
printf("strToFound = [%s], nStrlen = %d, nCnt = %d\n", strToFound, nStrlen, nCnt);
printf("strKeywords[arrayFoundIdxs[nCnt]] = [%s], nBeg = %d, nChange = %d\n",
strKeywords[arrayFoundIdxs[nCnt]], nBeg, nChange);
exit();
// switch (cmpType)
// {
// case 0:
// p = strstrs(strToFound, strKeywords, nCnt + 1, &nFound);
// break;
// case 1:
// p = strstrs_ext(strToFound, strKeywords, nCnt + 1, &nFound);
// break;
// default:
// p = strstrs_normal(strToFound, strKeywords, nCnt + 1, &nFound);
// break;
// }
}
} strToFound[nStrlen] = cBak;
}
double end = GetTickCount();
//函数类型 关键字序列 耗时 总共找到次数
printf("RESULT: %d %d %f %d\n",
cmpType, nCnt + , end - start, nFoundCnt);
fflush(stdout);
fflush(stderr); // if (nFoundCnt == 499)
// {
// printf("pre strToFound = [%s], strBackup = [%s], nCnt = %d nBeg %d nChange %d idxKeyword %d strKeywords[idxKeyword] %s\n",
// strToFound, strBackup, nCnt, nBeg, nChange, idxKeyword, strKeywords[idxKeyword]);
// } if (bSetFound)
{
memcpy(strToFound + nBeg, strBackup, nChange);
}
//
// if (nFoundCnt == 499)
// {
// printf("strToFound = [%s], nCnt = %d nBeg %d nChange %d idxKeyword %d\n", strToFound, nCnt, nBeg, nChange, idxKeyword);
// }
} double total_end = GetTickCount();
fprintf(stderr, "总共耗时[%f]\n", total_end - total_start);
} //TODO: 此处应该要释放内存
delete []strToFound;
delete []strBackup;
for (int i = ; i < max_keyword; i++)
{
delete []strKeywords[i];
}
}
函数效率比较图:
0 代表strstrs
1 代表strstrs_ext
2 代表strstrs_normal
可以看出,strstrs_ext比较稳定,而且效率也比较高。
在关键字列表都与查找字符串不匹配情况trstrs_normal表现好过strstrs
在关键字列表都与查找字符串基本都存在匹配项情况strstrs表现好过strs_normal
在任何情况下strstrs_ext都表现 最好
一个在字符串中查找多个关键字的函数strstrs(三种不同算法实现及效率分析)的更多相关文章
- 网络中,FIFO、LRU、OPT这三种置换算法的缺页次数
FIFO.LRU.OPT这三种置换算法的缺页次数 转载 由于要考计算机四级网络,这里遇到了问题,就搜了一些资料来解疑. 考虑下述页面走向: 1,2,3,4,2,1,5,6,2,1,2,3,7,6,3 ...
- C++中三种传递参数方法的效率分析
众所周知,在C++中有三种参数传递的方式: 按值传递(pass by value) #include <iostream> using namespace std; void swap(i ...
- js实现从字符串中查找出现次数最多的字符的两种解决办法
方法一:正则表达式匹配 var str = "adadfdfseffserfefsefseeffffftsdg"; ; var result = ""; whi ...
- 1.3 正则表达式和Python语言-1.3.5使用 search()在一个字符串中查找模式(搜索与匹配 的对比)
1.3.5 使用 search()在一个字符串中查找模式(搜索与匹配的对比) 其实,想要搜索的模式出现在一个字符串中间部分的概率,远大于出现在字符串起始部分的概率.这也就是 search()派上用场的 ...
- hiho1482出勤记录II(string类字符串中查找字符串,库函数的应用)
string类中有很多好用的函数,这里介绍在string类字符串中查找字符串的函数. string类字符串中查找字符串一般可以用: 1.s.find(s1)函数,从前往后查找与目标字符串匹配的第一个位 ...
- Excel-判断一个文本字符串中是否包含数字! 判断一个文本字符串是否是纯汉字!
0.判断一个文本字符串中是否包含数字!/判断一个文本字符串是否是纯汉字! 公式=IF(LENB(A1)=2*LEN(A1),"都是汉字","含有非汉字字符") ...
- ARM微处理器中支持字节、半字、字三种数据类型,地址的低两位为0是啥意思?
问题: ARM微处理器中支持字节.半字.字三种数据类型,其中,字需要4字节对齐(地址的低两位为0).半字需要2字节对齐(地址的最低位为0).我想问的是括号中的内容是什么意思呢?请牛人帮忙解释一下!谢谢 ...
- PAT 10-1 在字符串中查找指定字符
百度了一下另外两位同学的做法,都是先判断是否匹配,然后再用一个for()循环输出,我当然也是先判断,然后,就直接puts(),还是巧妙一点,题设要求及代码实现如下 /* Name: Copyright ...
- [LeetCode] Find And Replace in String 在字符串中查找和替换
To some string S, we will perform some replacement operations that replace groups of letters with ne ...
随机推荐
- codevs 1281 Xn数列 (矩阵乘法)
/* 再来个题练练手 scanf longlong 有bug....... */ #include<cstdio> #include<iostream> #include< ...
- codevs 最佳落点(模拟)
/* 这题并没有A掉 自己电脑上运行ok提交就不对 预处理攻击范围 然后模拟 求大神看看有没有错误 Orz */ #include<iostream> #include<cstdio ...
- asp.net微信开发第四篇----已关注用户管理
公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成.一次拉取调用最多拉取10000个关注者的OpenID,可以通过 ...
- 【转】 自定义iOS7导航栏背景,标题和返回按钮文字颜色
原文:http://blog.csdn.net/mad1989/article/details/41516743 UIBarButtonItem,navigationItem,backBarButto ...
- Objective-C学习篇03—继承
大纲: 继承的基本概念 自定义初始化方法 便利构造器方法 重写description方法 一 继承基本概念 程序里的对象和"人类"的对象是一样的,高富帅继承了父母,自然就拥有了父母 ...
- C++普通函数与模板函数以及特化函数重载的优先级问题
在面对C++模板的时候,需要十分注意,因为模板的复杂性有很多情况,所以最好学习模板的方法我个人认为就是用到就去学,用不到就尽量别去看各种奇门怪技,因为你就算看了,好不容易搞懂模板的实现内部了,包括元编 ...
- 142 Linked List Cycle II(如果链表有环,找到入口结点Medium)
题目意思:如果有环,返回入口结点 思路:先判断有没环,再计算环的结点数,然后p1指向头,p2往后移结点次数,p1.p2相遇为入口结点 ps:还是利用指针间距这个思路 /** * Definition ...
- ul ol 列表的样式的控制
ul( Unordered List)无序列表 ol(Ordered List)有序列表 列表的样式: 列表原有符号.自定义图形符号.符号显示位置. 1.列表符号 是显示于每一个列表项目前的符号标识. ...
- jquery easy ui 学习 (5) windowlayout
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 获取win7时区所有信息
打开命令行工具: tzutil /l # 或者输入到文件中tzutil /l > data.txt # -*- utf-8 -*- """获取win7所有时区信息, ...