1.清除空格
編寫一個程序,把字符串中的每個空格清除掉。例如輸入“We are happy.”,則輸出“Wearehappy.”。
- 編程思路
由於字符串的內存分配方式是連續分配的。我們從字符串當中刪除一個空格字符時,需要把后面所有的字符往前移動一個字節的位置。但如果每次刪除都需要移動字符串后面的字符的話,對於一個長度為n 的字符串而言,刪除一個空格字符的時間復雜度為O(n) 。而對於本題而言,有可能要刪除的空格字符的個數是n ,因此該方法就刪除而言的時間復雜度為O(n2) 。
事實上,我們並不需要在每次刪除一個空格的時候都去移動后面所有的字符。我們可以設想,當一個空格需要被刪除的時候,我們把它所占的位置讓它后面的字符來填補,也就相當於這個空格被刪除了。具體方法為:
(1)定義兩個指針p1和p2,p2用於遍歷原始字符串,p1用於指向結果字符串中當前賦予的非空格字符。初始狀態都指向字符串首字符。
(2)如果p2指向的元素不為空格,那么將p2指向的內容賦值給p1,然后p1和p2指向下一個元素;如果p2指向的內容為空格,那么p2指向下一個元素,p1保持不動。
(3)直到p2指向字符串末尾的“\0”時,清除空格結束。
- 源程序及運行結果
#include<iostream>
using namespace std;
int main()
{
char str[81];
cin.getline(str,80,'\n');
//設置兩個指針指向數組首元素
char *p1=str;
char *p2=str;
while(*p1!='\0')
{
if(*p2!=' ') //如果p2指向不為空格,則將p2指向內容復制給p1指向
*p1++=*p2++;
else //如果p2指向為空格,則p2指針向前移動一格。
p2++;
}
cout<<str<<endl;
return 0;
}
上例刪除字符串中的所有空格,在實際應用中,有時空格需部分保留,如字符串中的多個連續空格,則保留1個。這樣,可以將這個問題進行擴展,對給定字符串,刪除開始和結尾處的空格,並將中間的多個連續的空格合並成一個。
2.清除多余空格
編寫一個程序,對給定的字符串,刪除開始和結尾處的空格,並將中間的多個連續的空格合並成一個。例如輸入" We are happy. ",則輸出"We are happy."
- 編程思路
因為需要刪除開始和結尾處的空格,而字符串中間的空格又需要保存一個,因此需要進行另外的處理。可以通過設置一個標識位來進行處理,定義一個bool變量flag表示是否保存一個空格,如果flage=true表示保存一個空格,如果flag=false則不保存空格。初始化的時候將flag設為false,這樣開始階段的空格都不會被保存,當碰到一個不為空格的字符時,保存該字符,然后設置flag=true表明會保存后面待掃描的字符串中的第一個空格,這樣在碰到第一個空格時就能夠保存。
按上面的操作方法,掃描結束后,目標字符串的結尾要么是非空格字符,要么是一個空格字符,這樣進行一次判斷就好了,如果是空格字符,這將該空格設為“\0”,如果不為空格字符,則在其后面加上“\0”。
- 源程序及運行結果
#include<iostream>
using namespace std;
int main()
{
char str[81];
cin.getline(str,80,'\n');
int index=0;
bool flag=false;
for(int i=0;str[i]!='\0';i++)
{
if(str[i]!=' ') // 如果遍歷到的是非空格字符,則進行賦值
{
str[index++]=str[i];
flag=true; // 表示允許保存一個空格
}
else if(flag) // 如果允許有一個空格
{
str[index++]=str[i];
flag=false;
}
}
if(index>0&&str[index-1]==' ') //處理字符串最后的多余空格
{
str[index-1]='\0';
}
else
{
str[index]='\0';
}
cout<<str<<endl;
return 0;
}
在網絡編程中,如果URL參數中含有特殊的字符,如空格、“#”等,導致服務器端無法識別時,就把這些特殊的字符轉換成可以識別的字符。轉換規則是:%加上十六進制的ASCII碼,例如空格的ASCII碼是32(16進制為0x20),就被替換成%20。
3.替換空格
編寫一個程序,把字符串中的每個空格替換成“%20”。例如輸入“We are happy.”,則輸出“We%20are%20happy.”。
- 編程思路
將長度為1的空格替換為長度為3的“%20”,字符串的長度會變長。如果另外開辟一個新的數組來存放替換空格后的字符串,那么這個問題非常容易解決。設置兩個指針分別指向新舊字符串首元素,遍歷原字符串,如果碰到空格就在新字符串中填入“%20”,否則就復制原字符串中的內容。但這種新開辟數組保存結果字符串的做法,會造成空間的浪費。
如果在原字符串后面有足夠多的空余空間,可以在原來的字符串上做替換。下面來探討替換的方法。
因為把空格替換為”%20“,每次替換多2個字符,因此在可以統計出原來字符串的長度和其中空格的總個數后,計算出結果字符串的長度為“原字符串長度 + 2*空格數 ”。
替換操作從后往前進行,思路為:遇到非空格,直接搬到后面;遇到空格,替換為“%20”。 直到待插入位置指針和原字符串的掃描指針的位置重合。具體過程描述為:
(1)首先遍歷原字符串str,統計出原字符串的長度strlen以及其中的空格數量blanknum。
(2)根據原字符串的長度和空格的數量,求出結果字符串的長度newlen,即newlen=strlen+blanknum*2。
(3)定義兩個指針p1和p2分別指向原字符串和結果字符串的末尾位置,即p1=str+strlen、 p2=str+newlen。
(4)如果p1指向內容不為空格,那么將內容直接賦值給p2指向的位置,且p2指針前移;如果p1指向內容為空格,那么從p2指向位置開始賦值“02%”。
(5)p1指針前移。
(6)直到p1==p2時,表明字符串中的所有空格都已經替換完畢。
例如,按上述操作過程,將字符串“Hello world ”中的空格進行替換的操作如圖1所示。
圖1 空格替換操作過程
- 源程序及運行結果
#include<iostream>
using namespace std;
int main()
{
char str[81];
cin.getline(str,80,'\n');
int strlen=0;
int blanknum=0;
int i=0;
//求字符串長度和空格數量
while(str[i]!='\0')
{
strlen++;
if(str[i]==' ')
blanknum++;
i++;
}
int newlen=strlen+blanknum*2;//求新字符串長度
if(newlen>=80)
{
cout<<"替換后,串超過了預定義的長度。"<<endl;
return 0;
}
//設置兩個指針指向新舊數組末尾
char *p1,*p2;
p1=str+strlen; p2=str+newlen;
//當上面兩個指針指向同一個元素則表明沒有空格
while(p1>=str && p2>p1)
{
if(*p1==' ')
{
*p2='0'; p2--;
*p2='2'; p2--;
*p2='%'; p2--;
}
else
{
*p2=*p1; p2--;
}
p1--;
}
cout<<str<<endl;
return 0;
}