數據結構18: 數據結構中的字符串


數據結構中的字符串
字符串BF算法(普通模式匹配算法) 
數據結構中提到的串,即字符串,由 n 個字符組成的一個整體( n >= 0 )。這 n 個字符可以由字母、數字或者其他字符組成。

例如,S = ”BEIJING” ,S 代表這個串的串名,BEIJING 是串的值。
雙引號不是串的值,作用只是為了將串和其他結構區分開。
特殊的串
空串:含有零個字符的串。例如:S = “”(雙引號中沒有任何東西),一般直接用 Ø 表示。

空格串:只包含空格的串。注意和空串區分開,空格串中是有內容的,只不過包含的是空格,且空格串中可以包含多個空格。例如,a = ”   ”(包含3個空格)。

子串與主串:串中任意個連續字符組成的字符串叫做該串的子串,包含子串的串稱為主串。
例如:a = ”BEI”,b = ”BEIJING”,c = ”BJINGEI” 。對於字符串 a 和 b 來說,由於 b 中含有連續的字符串 a ,所以可以稱 a 是 b 的子串,b 是 a 的主串;而對於 c 和 a ,雖然 c 中也含有 a 的全部字符,但不是連續的 “BEI” ,所以串 c 和 a 沒有任何關系。

子串在主串中的位置:對於串 a = ”BEI” 來說,首字符 ‘B’ 在串 b 的位置為 1 ,所以子串 a 在主串 b = “BEIJING” 中的位置是 1。
子串在主串中的位置和字符在數組中的存放位置不同,子串在主串的位置從 1 開始數。
兩個串相等的標准:如果兩個串的串值完全相同,那么這兩個串相等。
串的三種存儲結構
存儲串的結構有三種:1 定長順序存儲;2 堆分配存儲; 3 塊鏈存儲。
定長順序存儲
采用固定長度的數組(即靜態數組)存儲串。

例如:char a[7] = "abcdfg";

此方式存儲串時,需要預估串的長度提前申請足夠的存儲空間。目標串如果超過了數組申請的長度,超出部分會被自動舍棄(稱為“截斷”)。

例如:char a[3] = "abcdfg";  //實際上數組中只存儲了 “ab” ,后邊的被截斷。
堆分配存儲
采用動態數組存儲串。
在C語言中,存在着一個被稱之為“堆”的自由存儲區,用 malloc 函數和 free 函數管理,malloc 函數負責申請空間,free 函數負責釋放空間。
例如:char * a = (char*)malloc(5*sizeof(char));//創建 a 數組,動態申請5個 char 類型數據的存儲空間

使用堆分配存儲的優勢在於:當發現申請的空間不夠用時,可以通過 realloc() 函數重新申請更大的存儲空間。

例如:a = (char*)realloc(a, 10*sizeof(char));//前一個參數指申請空間的對象;第二個參數,重新申請空間的大小

使用 malloc 函數申請的存儲空間,不會自動釋放,需要程序員調用 free() 函數手動釋放。如果不手動釋放,當程序執行徹底結束,由操作系統進行回收。

例如:free(a);//釋放動態數組a申請的空間

舉一個完整的例子,連接串 “abc” 和 “defg” 變為 “abcdefg” ;
#include
<stdio.h> #include <stdlib.h> #include <string.h>
int main() { char *a1 = NULL; char *a2 = NULL; a1 = (char*)malloc(3*sizeof(char)); strcpy(a1, "abc");  //將字符串“abc”復制給a1 a2 = (char*)malloc(3*sizeof(char)); strcpy(a2, "defg"); int lengthA1 = strlen(a1); int lengthA2 = strlen(a2); if (lengthA1 < lengthA1+lengthA2)
   { a1
= (char*)realloc(a1, (lengthA1+lengthA2)*sizeof(char)); } for (int i=lengthA1; i<lengthA1+lengthA2; i++)
   { a1[i]
= a2[i-lengthA1]; } printf("%s", a1); free(a1); free(a2);
return 0; }

輸出結果: abcdefg 注:在程序中,我們給 a1 和 a2 賦值的時候,使用了 strcpy 復制函數。在這里不能直接用:a1
= ”abc”這種方式,如果你這樣做,程序編譯會出錯,告訴你,沒有 malloc 的空間不能 free 。 原因是: strcpy 函數是將字符串復制到申請的存儲空間中,而直接賦值是字符串存儲在別的內存空間(本身是一個常量,放在常量區)中,更改了指針 a1 和 a2 的指向,也就是說,之前動態申請的存儲空間雖然申請了,結果還沒用呢就丟了。 塊鏈存儲 塊鏈存儲,其實就是借用鏈表的存儲結構來存儲串。一般情況下使用單鏈表就足夠了,而且不需要增設頭結點。 在構建鏈表時,每個結點可以存放一個字符,也可以存放多個字符。 圖1 塊鏈存儲 鏈表中最后一個結點的數據域不一定全被串值占滿,通常會補上 “#” 或者其他特殊的字符和字符串中的字符區分開。 每個結點設置字符數量的多少和存儲的串的長度、可以占用的存儲空間以及程序實現的功能相關。 如果串包含數據量很大,但是可用的存儲空間有限,那么就需要提高空間利用率,相應地減少結點數量(因為多一個節點,就多申請一個指針域的空間)。 而如果程序中需要大量地插入或者刪除數據,如果每個節點包含的字符過多,操作字符就會變得很麻煩,為實現功能增加了障礙。 總結 在平時編寫程序,經常會用到例如:char *a = ”abcd”;這種方式表示字符串,和上面三種存儲方式最主要的區別是:這種方式用於表示常量字符串,只能使用,不能對字符串內容做修改(否則程序運行出錯);而以上三種方式都可以對字符串進行刪改的操作。 例如: #include <stdio.h> int main()
{
char* a="abcd"; a[1]='b'; return 0; }
程序編譯可以通過,運行失敗,改成下面堆分配存儲的方式就對了:
#include
<stdio.h> #include <stdlib.h> #include <string.h>
int main()
{
char * a = (char*)malloc(4*sizeof(char)); strcpy(a, "abcd"); a[1] = 'e'; printf("%s", a); return 0; }

輸出結果:
aecd 三種存儲表示方式中,最常用的是堆分配存儲,因為它在定長存儲的基礎上通過使用動態數組,避免了在操作串時可能因為申請存儲空間的不足而丟失字符數據;
和塊鏈存儲方式相比,結構相對簡單,更容易操作。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM