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

字符串处理中的常见问题总结(一)

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是一个必须要掌握的算法,以后会经常用到,在多次编写后会增加对其的理解。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值