天天看點

ACM講課之字元串一、什麼是字元串二、字元串操作

本次講課講全面介紹字元串以及如何使用字元串解決具體問題。

一、什麼是字元串

1.如何存儲字元串

平時我們使用的變量有很多,int代表整型變量,double代表浮點型變量,char代表字元型變量,那麼對于一個字元串例如“Hello World!”應該如何存儲并操作呢。

在C語言裡,我們可以char數組進行存儲,例如:

1 char str1[] = "Hello World!";
2 char* str2 = "Hello World!";
3 char str3[20] = "Hello World!";      

對str1、2、3進行輸出都為“Hello World!”,這三種方式構造一個字元串的差別有哪些?我們輸出他們的空間長度(注意是占用的空間長度而不是字元串長度)。

1     int len1 = sizeof(str1)/sizeof(char);
2     int len2 = sizeof(str2)/sizeof(char);
3     int len3 = sizeof(str3)/sizeof(char);
4     printf("%d\n%d\n%d\n",len1,len2,len3);
結果為:13
    4
    20      

(此處應對上訴結果進行解釋說明 ==)

既然字元串可以存儲在一個字元數組裡面,那麼如何對字元串進行操作想必也就非常清楚了。需要注意的是,對于計算機可以字元和一個整型變量沒有任何差別,它們都是資料,是以對整型變量可以做的操作都可以對一個字元進行同樣的操作。

2.ASCII編碼

衆所周知字元在C/C++裡面是以ASCII碼的形式存儲在計算機中,既然字元串是存儲在字元數組裡面的,其實也就是多個字元的一個有序集合。它也遵守和字元同樣的的規則,例如'A'的ASCII碼為65,如果我們進行下列語句

1 char ch = 'A';
2 if(ch == 'A'){
3     ch = ch + 5;        
4 }
5 else {
6     ch = ch - 1;  
7 }      

那麼這裡ch的值應該變成多少了呢?此時的ch又代表哪個字元呢?

3.std::string

是不是沒見過這是什麼東西,它其實就是character string(字元串),這是一個C++的語句,意思就是調用std(标準命名空間)裡面的string類,可能你也已經猜到了string是用來幹什麼的,是的它可以直接定義一個字元串變量,并且能夠直接對串進行操作。

什麼意思呢?我們既然已經能夠用字元數組存儲字元串了,為什麼還需要多個string呢,因為我們前面說了字元串數組相當于一個字元的有序集合,歸根到底還都是單個字元,而字元串變量string才是真正的字元串,它可以直接對串操作,例如下列語句:

std::string str = "Hello";
str += " World";
str += "!";      

如果僅僅隻是這樣,那麼string并不顯得強大,事實上string支援下面的功能

我是傳送門:string的用法

但是值得注意的是,string是c++語言的東西,在c語言中并不能使用,而且string隻能通過cin流進行讀入操作,同樣可以使用下标對string字元串進行每一位的通路以及操作。

C++也還有很多C語言沒有的容器,通過這些容器對做題有很大幫助,而且這些容器對于一個ACMer來說是必須要掌握的,詳情請戳:

STL容器(Stack, Queue, List, Vector, Deque, Priority_Queue, Map, Pair, Set, Multiset, Multimap)

二、字元串操作

1.空格、換行符

我們知道使用scanf("%s",s);讀入一個字元串遇到空格和換行符自動跳出,但是對于一個字元串不可能都沒有空格以及換行呀,如果是需要讀入一個句子那該怎麼辦呢,對于C語言,我提供了下列幾種方法供參考

1 //方法一——判斷是否為空格選擇繼續讀入還是跳出
 2     char s[100],ch;
 3     scanf("%s",s);
 4     ch = getchar();
 5     while(ch == ' '){
 6         int len = strlen(s);
 7         s[len] = ' ';
 8         scanf("%s",s+len+1);
 9         ch = getchar();
10     }
11 
12 //方法二——利用格式符%[]設定結束符
13     char s[100];
14     scanf("%[^\n]",s);
15 
16 
17 //方法三——利用不安全的gets進行讀入
18     char s[100];
19     gets(s);      

三種方法都可以進行讀入以換行符為結束符帶有空格的字元串,但是我推薦最好使用第一種,為什麼?

(此處應對上述進行解釋說明)

在C++語言中,想要讀入這樣的串,我也同樣提供幾種方法供參考

1 //方法一——使用cin流對字元串進行讀入
2     char s[100];
3     cin.getline(s,100);
4 
5 //方法二——使用getline進行string類讀入
6     string s;
7     getline(cin,s);      

下面以一個例題為例,對字元串的具體操作進行講解

題目連結:

http://120.78.128.11/Problem.jsp?pid=1716

下面我貼出C語言和C++語言的代碼

 C語言:

1 #include <stdio.h>
 2 #include <string.h>
 3 char s1[10005],s2[105];
 4 
 5 void read(char *s){
 6     int ch;
 7     scanf("%s",s);
 8     ch = getchar();
 9     while(ch == ' '){
10         int len = strlen(s);
11         s[len] = ' ';
12         scanf("%s",s+len+1);
13         ch = getchar();
14     }
15 }
16 
17 int main(){
18     int t;
19     scanf("%d",&t);
20     while(t--){
21         read(s1),read(s2);//讀入字元串
22         int len1 = strlen(s1),len2 = strlen(s2);
23         int flag = -1,i,j;
24         for(i = 0; i < len1; i++){
25             if(s1[i] == s2[0]){
26                 for(j = 0; j < len2; j++){
27                     if(j == len2-1 && s1[i+j] == s2[j])
28                         flag = i+1;
29                     if(s1[i+j] != s2[j])
30                         break;
31                 }
32             }
33         }
34         printf("%d\n",flag);
35     }
36     return 0;
37 }      

C++語言:

1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 string s1,s2;
 5 
 6 int main(){
 7     int t;
 8     cin>>t;
 9     cin.get();
10     while(t--){
11         getline(cin,s1),getline(cin,s2);
12         int pos = s1.find(s2);
13         cout << (pos==-1?-1:pos+1) << endl;
14     }
15     return 0;
16 }      

這也是為什麼要用C++的原因,C++内置函數以及操作實在是太強大了,兩個C中較為冗長的函數在C++中都隻要用一句便實作了。

另一個例題:

http://120.78.128.11/Problem.jsp?pid=1924

C語言代碼:

1 #include <stdio.h>
 2 #include <string.h>
 3 char s[1000005];
 4 
 5 void read(char *s){
 6     int ch;
 7     scanf("%s",s);
 8     ch = getchar();
 9     while(ch == ' '){
10         int len = strlen(s);
11         s[len] = ' ';
12         scanf("%s",s+len+1);
13         ch = getchar();
14     }
15 }
16 
17 int main(){
18     int t,i;
19     scanf("%d",&t);
20     while(t--){
21         read(s);
22         int len = strlen(s);
23         for(i = 0; i < len; i++){
24             if(i == 0){
25                 putchar(s[i]-32);
26             }
27             if(s[i] == ' '){
28                 putchar(s[i+1]-32);
29             }
30         }
31         puts("");
32     }
33     return 0;
34 }      

C++代碼:

1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 string s;
 5 
 6 int main(){
 7     int t;
 8     cin>>t;
 9     cin.get();
10     while(t--){
11         getline(cin,s);
12         int len = s.size();
13         cout << char(s[0]-32);
14         for(int i = 1; i < len; i++){
15             if(s[i] == ' ')
16                 cout << char(s[i+1]-32);
17         }
18         cout << endl;
19     }
20     return 0;
21 }      

2.字元串比較

我們知道可以通過一位一位的模拟進行字元串比較,但要是兩個字元串都很長怎麼辦,我們容易得出暴力方法進行比對的時間複雜度為O(n*m),n和m就是兩個字元串的長度,通過一些算法我們可以進行比對優化,例如我們可以利用KMP算法在O(n+m)的時間複雜度内進行比對。

下面是KMP的算法講解

我是傳送門:KMP算法 傳送門:KMP例題

繼續閱讀