求职宝典 第二章 字符串

1. 字符串与子串、子序列

字符串是由零个或多个字符组成的有限串行,子串的定义是串中任意个连续的字符组成的子序列,并规定空串是任意串的子串,任意串是其自身的子串,

2. C风格字符串

C++ 语言通常通过char*/const char*类型的指针来C语言中的风格字符串。一般来说,我们使用指针的算数操作符来遍历C风格字符串,每次对指针进行测试并递增1,直到到达字符串null为止。

3. 标准库提供的字符串处理函数

C++提供了众多的字符串处理函数,主要如下:

 1)Strlen

Strlen计算字符数组的字符数,以’\0’为结束标志,计算不为’\0’的元素的个数。

自定义函数实现strlen的功能是:

Int strlen(const char * str)

{

   Assert(strlen != NULL);

   Int len = 0;

   While((*str++) != ‘\0’))

     Len++;

   Return len;

}

 2)Strcmp

即两个字符串自左向右逐个字符比较(按ASCALL 值的大小比较),直到出现不同的字符或遇’\0’为止。若s1s2相等,返回0;若s1大于s2,返回正数,若s1小于s2,则返回负数。

自定义实现strcmp函数的功能:

Int  strcmp(const char * str1const  char * str2)

{

   Assert(str1 != NULL && str2 != NULL);

   While(!(ret =*(unsigned char* )str1 - *(unsigned char*)str2 ) && *str1)

   {

      Str1++;

      Str2++;

   }

   If(ret<0)

      Ret = -1;

   Else if(ret > 0)

      Rer = 1;

  

    Return ret;

}

 3)Strcatstrcpy

Strcat(dest, src)把所指字符串添加到dest结尾处(覆盖dest结尾处的’\0’)并添加’\0’;

Strcpy(dest, src)把从src开始且含有null结束符的字符串复制到以dest开始的地址空间。

传递给标准库函数strcatstrcpy的第一个参数数组必须具有足够大的空间存放新生的字符串。

自定义函数实现strcat函数的功能:

Char * strcat(char * strDest, const char * strSrc )

{

   Char * address = strDest;

   Assert((strDest != NULL)&&(strcat != NULL));

   While(*srcDest)

      srcDest++;

   While(*strDest++ = *strSrc++)

   Return address;

}

自定义函数实现strcpy()函数的功能:

Char* strcpy(char * strDestination, const char * strSource)

{

   Assert((strdestination != NULL) && (strSource != NULL));

   Char *strD = strdestination;

   While((*strdestination++ = *strsource++) != ‘\0’) ;

   Return strD;

}

4)memcpy memset

 Memcpy函数

 Void * memcpy(void * dest, const void *src, size_t n);

功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中,函数返回指向dest的指针。

 Strcpymemcpy的比较

  1)复制的内容不同,前者只能复制字符串,后者可以复制任意内容。

  2)复制方法不同,前者不用指定长度,遇到被复制的字符串结束符’\0’时才结束,容易溢出,后者则是根据其第三个参数决定复制的长度。

  3)用途不同,通常复制字符串时用strcpy,而复制其它类型字符时用memcpy

  Memset函数

 Void* memset(void *s , int ch, size_t n);

功能:作用是将s中前n个字节用ch替换并返回s,作用是在一块内存中填充某个给定的值,他是对较大的结构体或数组进行清零操作的一种最快方法。

 

4.字符串的实际应用

  1)字符串包含问题

   可以用两种方法解决,第一种是串的模式匹配算法,第二种是KMP算法

   如:给定一个字符串A,要求在A中查找一个子串B

    深入串的模式匹配算法(普通算法和KMP算法)的详解

     串的定位操作通常称作串的模式匹配,是各种处理系统中的最重要操作之一。
模式匹配最朴素的算法是回溯法,即模式串跟主串一个字符一个字符的匹配,当模式串中跟主串不匹配时,主串回溯到与模式串匹配开始的下一个位置,模式串回溯到第一个位置,继续匹配。算法的时间复杂度为Om*n),算法如下:

//朴素的串的模式匹配算法,S为主串,T为模式串,即找S中有没有与T相同的字串
int Index(char *S, char *T, int pos)//pos记录从哪一位开始匹配可以直接用0代替
{
 int i=pos, j=0; 
 while(i <strlen(S) && j <strlen(T))//确保未超出字符串的长度
 {
  if (S[i] == T[j])
      { ++i; ++j;} //如果相同,则继续向后比较
  else 
      {i = i-j+1; j =0;} //如果不同,就回溯,重新查找
 }
 if (j == strlen(T))
  return i-strlen(T); //若匹配成功,返回S中与T字符串相同开始位置的索引
 else return 0; //若匹配不成功,返回0
}

 

O(m*n)的时间复杂度有点大,于是人们发现了KMP算法,核心思想是:当不匹配发生时,主串不回溯,模式串回溯到“合适”的位置,哪个位置合适,只与模式串有关,所以可以先算出模式串中各个字符,当不匹配发生是,应该回溯到哪个位置。算法整体时间复杂度O(m+m)。

 

void GetNext(char* T, int *next)
{
 int i=1,j=0; 
 next[1]=0;
 while( i < strlen(T) )
 { 
  if (j == 0 || T[i] == T[j])
  {
    ++i; ++j; 
    next[i] = j;
  } 
  else j = next[j];
 }

int KMP(char* S, char* T, int pos)
{
 int i = pos, j = 1;
 while (i)
 {
  if (S[i] == T[j])
  { 
   ++ i;  ++ j;
  } 
  else 
   j = next[j]; 
 }
 if (j > strlen(T)) 
  return i-T[0];
 else 
  return 0; 

求next的操作不是最优的,因为他没有考虑aaaaaaaaaaaaaaaaaaab的情况,这样前面会出现大量的1,这样的算法复杂度已经和最初的朴素算法没有区别了。所以稍微改动一下:

void GetNextEx(char *T, int *next)
{
 int i=1,j=0; next[1] = 0;
 while(i < strlen(T))
 {
  if (j == 0 || T[i] == T[j])
  {
   ++i; ++j;
   if (T[i] == T[j])
    next[i] = next[j];  //减少回退次数
   else   next[i] = j;  //和上面算法一样next[i]=j
  }
  else j = next[j]; 
 } 
}  

 

2)字符串移位包含问题 (略)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值