數據結構(六)串
串的基本概念
1、串的基本概念
字符串(String)是由零個或多個字符組成的有限序列。記為: S = ′a1 a2 … an′( n ≥ 0 ) 其中 S 是串的名字,用單引號括起來的字符序列是串的值,每個 ai( 1 ≤ i≤ n)可 以是字母、數字或其他字符。 n 是串中字符的個數,稱為串的長度,n=0 時的串稱為空串( Null String)。
需要特別指出的是,串值必須用一對單引號括起來( C 語言中是雙引號),但單引號是界限符,它不屬於串,其作用是避免與變量名或常量混淆。
·子串:串中任意個連續的字符組成的子序列稱為該串的子串。
·主串:包含子串的串相應地稱為主串。可見,子串是主串的一部分。
· 子串在主串中的位置:通常將字符在串中的序號稱為該字符在串中的位置。子串在主串中的位置則以子串的第一個字符在主串中的位置 來表示。
串相等:當且僅當兩個串的值相等時,稱這兩個串是相等的,即只有當 兩個串的長度相等,並且每個對應位置的字符都相等時才相等。
串也是一種特定的線性表,串的邏輯結構和線性表極為相似,其特定性僅在於串的數據對象限定為字符集。
2、串的抽象數據類型定義如下:
ADT String {
數據對象: D={ ai | ai∈ CharacterSet,記為 V,i=1 ,2 ,…, n,n≥ 0 }
結構關系: R={< ai,ai + 1 >| ai,ai + 1 ∈ V,i=1 ,…, n-1 ; n-1 ≥ 0 }
基本操作:
( 1 ) StrAsign( S,chars)
操作前提: chars 是字符串常量。
操作結果:生成一個值等於 chars 的串 S。
( 2 ) StrInsert( S,pos,T)
操作前提:串 S 存在,1 ≤ pos≤ StrLength( S)+ 1 。
操作結果:在串 S 的第 pos 個字符之前插入串 T。
( 3 ) StrDelete( S,pos,len)
操作前提:串 S 存在,1 ≤ pos≤ StrLength( S)+ 1 。
操作結果:從串 S 中刪除第 pos 個字符起長度為 len 的子串。
( 4 ) StrCopy( S,T)
操作前提:串 S 存在。
操作結果:由串 T 復制得串 S。
( 5 ) StrEmpty( S)
操作前提:串 S 存在。
操作結果:若串 S 為空串,則返回 TRUE,否則返回 FALSE。
( 6 ) StrCompare( S,T)
操作前提:串 S 和 T 存在。 操作結果:若 S>T,則返回值>0 ;如 S=T,則返回值=0 ;若 S<T,則返回值<0 。
( 7 ) StrLength( S)
操作前提:串 S 存在。
操作結果:返回串 S 的長度,即串 S 中的字符個數。
( 8 ) StrClear( S)
操作前提:串 S 存在。
操作結果:將 S 清為空串。
( 9 ) StrCat( S,T)
操作前提:串 S 和 T 存在。
操作結果:將串 T 的值連接在串 S 的後面。
( 10 ) SubString( Sub,S,pos,len)
操作前提:串 S 存在,1 ≤ pos≤ StrLength( S)且 1 ≤ len≤ StrLength( S)- pos+1 。
操作結果:用 Sub 返回串 S 的第 pos 個字符起長度為 len 的子串。
( 11 ) StrIndex( S,pos,T)
操作前提:串 S 和 T 存在,T 是非空串,1 ≤ pos≤ StrLength( S)。
操作結果:若串 S 中存在和串 T 相同的子串,則返回它在串 S 中第 pos 個字符 之 後第一次出現的位置;否則返回 0 。
( 12 ) StrReplace( S,T,V)
操作前提:串 S、 T 和 V 存在且 T 是非空串。
操作結果:用 V 替換串 S 中出現的所有與 T 相等的不重疊的子串。
( 13 ) StrDestroy( S)
操作前提:串 S 存在。
操作結果:銷毀串 S。
}ADT string
串的順序存儲結構
串的順序存儲結構有定長順序串、堆串。
1、定長順序串
定長順序串是將串設計成一種靜態結構類型,串的存儲分配是在編譯時完成的。
1)定長順序串存儲結構
定長順序串類型定義如下:
#define MAXLEN 40 typedef struct { /*串結構定義*/ char ch[ MAXLEN]; int len; }SString;
其中 MAXLEN 表示串的最大長度,ch 是存儲字符串的一維數組,每個分量存儲一 個字符, len 是字符串的長度。
2).定長順序串基本操作的實現
( 1 )串插入函數
【問題分析】在進行順序串的插入時,插入位置 pos 將串分為兩部分(假設為 A、 B,長度為 LA、 LB)及待插入部分(假設為 C,長度為 LC),則串由插入前的 AB 變為 ACB,由於是順序串, 插入會引起元素的移動。可能出現以下三種情況:
①插入後串長( LA+LC +LB)≤ MAXLEN,則將 B 後移 LC 個元素位置,再將 C 插入。
②插入後串長>MAXLEN 且 pos+LC≤ MAXLEN,則 B 後移時會有部分字符被舍棄。
③插入後串長> MAXLEN 且 pos +LC >MAXLEN,則 B 的全部字符被舍棄(不需後移),並 且 C 在插入時也有部分字符被舍棄。
【算法描述】
StrInsert(SString *s, int pos, SString t) /*在串 s 中下標為 pos 的字符之前插入串 t */ { int i; if (pos<0 || pos>s->len) return(0); /*插入位置不合法*/ if (s->len + t.len<=MAXLEN) { /*插入後串長≤MAXLEN*/ for (i=s->len + t.len-1;i>=t.len + pos;i--) s->ch[i]=s->ch[i-t.len]; for (i=0;i<t.len;i++) s->ch[i+pos]=t.ch[i]; s->len=s->len+t.len; } else if (pos+t.len<=MAXLEN) {/*插入後串長>MAXLEN,但串 t 的字符序列可以全部插入*/ for (i=MAXLEN-1;i>t.len+pos-1;i--) s->ch[i]=s->ch[i-t.len]; for (i=0;i<t.len;i++) s->ch[i+pos]=t.ch[i]; s->len=MAXLEN; } else { /*插入後串長>MAXLEN,並且串 t 的部分字符也要舍棄 for (i=0;i<MAXLEN-pos;i++) s->ch[i+pos]=t.ch[i]; s->len=MAXLEN; } return(1); }
實現順序串插入的算法其實現復雜度為: O( s->len+t.len)。
2、堆串
字符串包括串名與串值兩部分,而串值采用堆串存儲方法存儲,串名用符號表 存儲。
堆串存儲方法:仍以一組地址連續的存儲單元順序存放串中的字符,但它們的 存儲空間是在程序執行過程中是動態分配的。
串名符號表:所有串名的存儲映像構成一個符號表。借助此結構可以在串名和 串值之間建立一個對應關系,稱為串名的存儲映像。
1)堆串存儲表示: C 語言已經有一個稱為“堆”的自由存儲空間,並可用函數 malloc()和函數 free()完成動態存儲管理。
串的鏈式存儲與串的應用
1、塊鏈串
由於串也是一種線性表,因而也可以采用鏈式存儲。因為串是一個特殊的線性表(表中每 個元素就是一個字符)。在具體實現時,一個鏈表存放一個串值,每個結點既可以存放一個字符, 也可以存放多個字符。每個結點稱為塊,整個鏈表稱為塊鏈結構,為便於操作,再增加一個尾指 針。
塊鏈結構可定義如下:
#define BLOCK_SIZE 4 /*每結點存放字符個數 4*/ typedef struct Block{ char ch[BLOCK_SIZE]; struct Block *next; } Block; ? typedef struct { Block *head; Block *tail; int len; } BLString;
結點大小:鏈表中的結點分成兩個域data和link,其中結點大小是指data域中存放字符的個數,鏈域大小是指 link 域中占用字符的個數。
存儲密度=串值占用的存儲位/實際為串分配存儲位
顯然,串的存儲密度越小,運算處理就越方便,但存儲占用的量較大。應根據具體情況來確 定使用串的何種存儲結構。
結點大小等於 1 :當 BLOCK_SIZE 等於 1 時,每個結點存放 1 個字符,結構同線性鏈表,存 儲結構可定義如下,插入、刪除的處理方法和線性鏈表一樣,算法處理簡單,但存儲密度較低。
結點大於 1 :當 BLOCK_SIZE 大於 1 時,每個結點存放多個字符,當最後一個結點未存滿 時,不足處可用特定字符(如#)補齊。雖然存儲密度相對結點大小等於 1 的存儲方法來說,存儲 密度較高,但此時插入、刪除的處理方法比較復雜,需要考慮結點的分拆和合並。
2、串的應用舉例:簡單的行編輯器
數據結構(六)串