文章转自:http://blog.csdn.net/zhangmuyan/article/details/8721257
最近一直在研究字符串的问题,有关c的,也有c++string类的。看到这篇文章,正是我自己在学习的内容就转载了。
一般面试字符串的题目分四种:1, 基本运算(求长度,连接,比较)2. 格式转换(atoi, itoa) 3.字符串翻转 4. 模式匹配。
1. 基本运算
a. 赋值操作
函数原型:int StrAssign(const char *s, char *t)
函数说明:将s的内容付给t
函数定义:
int StrAssign(const char *s, char *t){
char *p = t;
while(*s !='\0'){
*p++ = *s++;
}
*p = '\0';
return 0;
}
b. 连接操作
函数原型:int Concat(char *s, const char *t)
函数说明:将串t连接到串s的尾部,形成一个新串
函数定义:
int Concat(char *s, const char *t){
//首先找到串s的尾部
char *p = s;
while(*p != '\0') p++;//循环结束以后的p就是s的尾部
while(*t !='\0') *p++ = *t++;
*p='\0';//添加尾部字符
return 0;
}
c.求长度
函数原型:int StrLen(char *s)
函数说明:返回串s的长度
函数定义:
int StrLen(char *s){
int len = 0;
while(*s != '\0'){
len ++;
s++;
}
return len;
}
d. 字符串比较
函数原型:int StrCmp(const char *s, const char *t)
函数说明:比较两个串的大小,返回值为-1,0,1表示s<t, s=t,s>t。
函数定义:
int StrCmp(const char *s, const char *t){
while((*s != '\0')&&(*t != '\0')){
if(*s++ - *t++ > 0) return 1;
else if( *s++ - *t++ <0) return -1;
else return 0;
}
return 0;
}
//不区分大小写的字符串比较函数
int stricmp(const char *s, const char *t){
while((*s != '\0')&&(*t != '\0')){
if(toupper(*s++) - toupper(*t++) > 0) return 1;
else if(toupper(*s++) - toupper(*t++) <0) return -1;
else return 0;
}
return 0;
}
2. 整数与字符串之间的相互转换
a.将字符串转换成整数
例如有一字符串str[]=“1234”,最直观的转换方法就是依次将每一个字符转换成相应的数字,然后乘10累加,即((1*10+2)*10+3)*10+4。想要得到每一位相应的数字,只需用每个字符减去数字0的ASCII码,即2= str[1]-'0'。
如果字符串首字符标示的是一个负数,即str[0]=='-'。那么此时应该设置一个符号判断标示位(用来判断以后得到的整数是否需要乘-1),并把要处理的字符数组下标设置为1。
int str_to_int(char str[])
{
int i=0, isNeg=0,num=0;
if(str[0]=='-')
{isNeg=1;
i=1;
}
while(str[i])
{num=num*10+(str[i]-'0');
i++;
}
if(isNeg)
num*=-1;
return num;
}
b.将整数转换为字符串
将整数转换为字符串相对要复杂些。通过取模,并结合商与余数的关系,可以有几种方法。例如,123除以100,商为1,余数为23,这样,首先可以把“1”保存到字符串里。然后23除以10,商为2,余数为3。这样就可以得到字符串“123”了。但是,怎样来确定整数的位数确实比较麻烦。有一种相对简单的方法。
首先将123除10取模,得到数字3,此时商为12。再将12除10取模,得到数字2,商为1。这样,我们可以得到字符串“321”,接着进行一次逆序即可得到想要的字符串。
同样,如果该整数小于0,我们需要人为地将其变成正数,再进行取模运算!!
char int_to_str(int num,char str[])
{
int i=0,j=0,isneg=0;
char temp[10];
if(num<0)
{
num*=-1;
isNeg=1;
}
do{
temp[i]=(num)+'0';
num/=10;
i++;
}while(num) //使用do-while结构保证当num为0时也执行循环。
if(isNeg)
temp[i++]='-';
while(i>0)
str[j++]=temp[--i];
str[j]='\0'; //字符串结束符不能忘掉。
}
3、字符串翻转,这里有两种翻转,第一种是翻转整个字符串,第二种是翻转句子中的单词。
a. 翻转整个字符串
函数原型:void Reverse(char *s1)
函数说明:"abcd"=>"dcba"
函数定义:
void Reverse(char *s1){
char *p = s1;
while(*p!='\0'){
p++;
}
char ch_t;
p--;
char *p1 = s1;
while(p1 < p){
ch_t = *p1;
*p1 = *p;
*p = ch_t;
p--;
p1++;
}
return;
}
b. 翻转句子中的单词
函数原型:void ReverseWord(char *s1)
函数说明:"today is sunday"=>"sunday is today"
函数定义:
void ReverseWord(char *c){
//先对整个句子进行翻转
char *p = c;
char *p1;
int count = 0;
//在对句子的每个单词进行翻转
while(*p!='\0'){
p++;
count++;
if((*p == ' ')||(*p =='\0')){
//记录下这个位置
p1 = p - count;
if(*p == ' ') p++;
ReverseChar(p1, 0, count-1);
count = 0;
}
}
Reverse(c);
}
在ReverseWord函数调用了ReverseChar函数对给出字符串的起始位置做翻转
void ReverseChar(char *ch, int start, int end){
char *p1 = ch;
char *p = ch;
char ch_t;
while(start < end){
ch_t = *(p1+start);
*(p1+start) = *(p + end);
*(p + end) = ch_t;
end --;
start++;
}
}
4、字符串的模式匹配
给一个串T,和子串P,返回是否子串p是否和串T中有子串匹配,如果有,返回位置;没有返回0。
假设P为给定的子串,T是待查找的字符串
T: t0 t1 t2 t3 .... tm-1 ... tn-1
P: p0 p1 p2 p3 .....pm-1
用P中的字符依次与T中的字符进行比较,遇到不相等的字符,则可将P右移一个字符,从新进行比较,直到某次匹配成功或者到达P的最右字符移出T为止。
如: 若P="aaaba", T="aaabbaaaba", 则匹配过程如下图
T: a a a b b a a a b a
P: a a a b a
a a a b a
.....
a a a b a
上述朴素字符串匹配算法的时间复杂性为0(M*N).
朴素匹配算法函数定义:
int Index(const char *res, const char *str, int position)
{
int i=0;
int j=0;
int lengthRes=strlen(res);
int lengthStr=strlen(str);
while(i<=lengthRes && j<=lengthStr)
{
if(res[i]==str[j])
{
++i;
++j;
}
else if(j == lengthStr)
return i-lengthStr;
else
{
//如果不匹配, j从头开始重新匹配
i=i-j+1;
j=0;
}
}
return -1;
}
在朴素的匹配算法中,从头回溯重新匹配是没有必要的。
KMP主要解决两个问题:
a. 当字符串比较出现不等时,确定下一趟比较前应该将P右移多少个字符;
b. P右移后,应该从哪个字符开始和T中刚才比较时不等的那个字符继续开始比较.
每当一趟匹配过程中出现字符比较不等时,不需回溯主串S的指针,而是利用已经得到的“部分匹配”结果将模式串向右“滑动”尽可能远的一段距离后,继续进行比较。模式串到底向右滑动多少,在KMP算法中是用一个数组来存储的。针对模式串中的每个索引j,都将有一个对应的值。此值的含义为模式串中位置从0到j-1构成的串中所出现的首尾相同的子串的最大长度加1。
因此,KMP算法计算next数组是关键。
void GetNext(char *p, int next[]){
int i,j, slen;
slen = strlen(p);
i = 0;
next[0] = -1;
j = -1;
while(i<slen){
if((j==-1)||(p[i] == p[j])){
++i;
++j;
next[i] = j;
}
else{
j = next[j];
}
}
}
KMP匹配算法函数:
int Index_KMP(char *s, char *p, int pos, int next[]){
int i,j, slen, plen;
i = pos -1;
j =-1;
slen = strlen(s);
plen = strlen(p);
while((i<slen)&&(j<plen)){
if((j == -1)||(s[i] == p[j])){
++i;
++j;
}
else{
j = next[j];
}
}
if(j>=plen) return i - plen;
else return -1;
}