您的位置:首页 > 其它

字符串常见问题总结(一)

2013-11-15 15:51 447 查看
字符串处理中的常见问题总结(一)
C语言中字符串处理方面的问题非常普遍,常见问题如:查找,替换,复制,移动,插入,删除,排序,单词统计,字符串类型与其他类型(整形,实型,长整形)之间的相互转换等。
一、 字符串的查找
C语言库函数<string.h>中有很多有关的函数,如:int strcpm(char * src, char*dest); int strncpm(char*,char*);char *strstr(char*, char*) (从字符串str1中查找是否有字符串str2,如果有,从str1中的str2位置起,返回str1中str2起始位置的指针,如果没有,返回null。); char* strchr(char*, char)(查找字符串s中首次出现字符c的位置)
其中strcmp(); strncmp();已经在常用库函数实现一文中说明了。下面给出strstr()和strchr()两个函数的实现。
首先是strchr();这个函数的实现比较简单,只需要一次遍历字符串就可以了,算法效率O(n)。
char * Mystrchr( const char * src, char ch)
{
assert(NULL!=src);
do
{
if(*src== ch)
{
return const_cast<char*>(src); /*由于传入的是一个const指针,因此在此要对其进行去const转换,这样不会影响结果。*/
}}while('\0' != *(src++));
return NULL;
}


其次实现strstr()函数,也就是模式串匹配的问题,这个问题有多种不同的解决办法,它们的执行效率也不相同。
首先是朴素匹配法(暴力检索),这种方法是比较容易想到的,但是它的执行效率O(n*m),即对回溯的对父串进行匹配。
char * Mystrstr_bf(char * par, char *form)
{
assert(NULL!=par&&NULL!=form);
char * tempS = par;
char *tempF = form;
int len  = strlen(form);
while('\0'!=*par&&strlen(par)>= strlen(form))
{
while(*tempS == *tempF&& *tempF!= '\0')
{
tempS ++;
tempF ++;
}
if(*tempF == '\0')
return tempS - len;
tempF = form;
par++;
tempS = par;
}

return NULL;
}


另一种比较常用的方法是KMP算法,该算法具有较高的效率,该算法的时间效率为O(m+n)m,n分别为父串和模式串的长度。该方法是基于不对父串回溯的方法,分析模式串得出next[]数组,然后利用next数组可以实现BMP算法,具体的分析可以参考http://blog.csdn.net/yaochunnian/article/details/7059486

char * KMP(const char *str, const char * pat) //KMP 实现方法
{
assert(NULL!=str && NULL!=pat);
int j = 0, k =-1;
int slen = strlen(str);
int plen = strlen(pat);
if(slen < plen)
return (char*)str;
int *next = new int [plen];
next[0] = -1;
while(j < plen)
{
if(k == -1 || pat[j] == pat[k])
{
j++;
k++;
next[j] = k;
}
else
k = next[k];
}
for(int i =0; i<plen; i++)
{
cout<<next[i];
}
cout<<endl;
/*
求取next数组,并输出next数组
*/
int ppos = 0, spos = 0;
while(ppos<plen && spos <slen)
{
if(ppos == -1 ||str[spos] == pat[ppos])
{
ppos++;
spos++;
}
else
ppos = next[ppos];
}
delete [] next;
if(ppos < plen)
return  NULL;
else
{
for(int i =0; i <spos-plen; i++)
str++;
return (char*)str;
}
}


此处也可以利用求next数组的方法求取一个字符串的最大相等前缀和后缀,不过此时要有些小的变动。
char *My_next(char *str)
{
assert(NULL!= str);
int j =0, k =-1;
int len = strlen(str);
int *next = new int [len +1];
next[0] = -1;
while(j <= len) //此时选择的是<=len
{
if(k == -1 || str[j] == str[k])
{
j++;
k++;
next[j] = k;
}
else
k = next[k];
}
char *temp = str + len - next[len];
delete []next;
return temp;
}


应用实例:从键盘上读入一批单词,统计其中某个单词出现的次数(如good);

int main()
{
char a[100];
char b[] = "good";
gets(a);
char *p1 = a;
char *p2 = b;
char *temp = NULL;
int n =0;
//char* result = KMP(a,b);
//cout<<result<<endl;
while(strlen(p1)>=strlen(p2))
{
if(temp = KMP(p1,p2))
{
p1 = temp;
n++;
}
p1++;
}
cout<<n<<endl;
return 0;
}


以上所用的KMP都可以用C语言的库函数strstr()代替,但是strstr()函数(查看visual studio 2010中的库函数)采用的是朴素搜索法,因此自己编写的KMP的效率是比库函数中的效率高的。KMP是一个必须要掌握的算法,以后会经常用到,在多次编写后会增加对其的理解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: