1. 程式人生 > >數據結構與算法系列研究三——字符串

數據結構與算法系列研究三——字符串

ext 其他 pty 算法實現 strcmp images troy hide ryu

字符串的研究和KMP算法分析和實現

一、串的定義

串是計算機非數值處理的基本對象。串是一種特殊的線性表,它的每個結點僅由一個字符組成,並且單個元素是無意義的。
1、串(string):是由0個或多個字符組成的有限序列,記作:
S=“a1a2...an” (n>=0)
其中:S是串名,兩個雙引號括起來的字符序列為串的值。雙引號不屬於串。
ai(1<=i<=n)為字母、數字或其它符號。
空格符是一個有效字符。
2、串中所有字符的個數n為串的長度。長度為0的串稱為空串。
3、空格串

:全部由空格符組成的字符序列。
4、子串:串中任意連續個字符的序列稱為該串的子串。
5、主串:包含該子串的串稱為主串。
6、字符在串中的序號稱為該字符在串中的位置
7、子串在串中的位置:用子串第一個字符在主串中的位置來表示。空串是任意串的子串。任意串是自身的子串。
8、串常量:不能改變其值的量為常量,串常量一般用直接量表示。
串變量:用於存放字符串值,並且其值可以改變的量。

相關運算:(黃色為基本子集,有這幾種操作可以產生其他復雜操作)
Strassign (&S,chars):將常數串賦值給S,對應於strcopy。
Strlength(S):求串S的長度,對應於strlen(s)。


Strcompare(S1,S2):比較串S1和S2,對應於strcmp(s1,s2)。
Concat(&S,S1,S2):將串S1和S2聯接成一個串,並賦給S。
Substring(&Sub,S,pos,len):在S串中求pos開始的長度為len的子串。
Clearstring(&S):將串S置成空串。
Strcopy (&S,S1):將串S1復制到變量S
Strempty(&S):判斷串S是否為空串。
Index(S,Sub,pos):求子串sub在串S的pos開始後出現的位置。
Replace(&S,Sub,T);用Sub替換S中所有與T相等的不重疊的子串。
Strinsert(&S,pos,Sub):在串S的pos位置前插入子串Sub。
Strdelete(&S,pos,len):在串S中刪除pos位置開始長度為len的子串。
Destroystring(&S):撤消串S。
串的表示與實現—堆分配存儲:

分配一組地址連續的與串長一致的存儲單元存放串值字符序列。與定長順序表示的區別:采用動態分配;串空間與串長一致,串長變化將引起串空間的重新分配。
堆存儲表示:

技術分享
typedef struct{
char *ch;
int length;
}HString

串的表示與實現—塊鏈表示
塊:一組連續的字符。
塊鏈存儲表示:把串分成指定等長的塊,每一塊用一個結點表示,把各塊鏈成一個鏈表。
當一個結點不滿時,用特殊字符(如‘#’)填充。
若塊的長度為1,就是以單字符為結點的鏈表結構。
塊的大小與存儲密度有關:存儲密度=串值所占存儲位/實際分配存儲位。

單字符結點:插入、刪除方便;存儲密度小,存儲占用量大。

技術分享

多字符結點:存儲密度大;插入、刪除存在結點的分離,降低存儲密度。

技術分享

二、字符串的KMP算法

2.1、串的模式匹配算法
串的模式匹配:求子串P在主串T中的位置的定位操作稱為串的模式匹配。
模式串:子串。
2.2、簡單的模式匹配算法:
從主串T的第一個字符起,與模式串P的第一個字符比較,若相等,則繼續逐個比較後繼字符,否則從主串T的第二個字符起再重新和模式串P的第一個字符比較。依次類推,直到模式串P中的每個字符依次和主串T中的一個連續的字符序列相等,則稱匹配成功,返回與P匹配的主串T的字符序列的第一個字符序號。否則稱匹配失敗,函數值為0(或-1)。簡單模式匹配算法存在的問題:在模式匹配過程中存在已比較的字符重復比較。實際上已比較過的字符不必重復比較。

技術分享
 1      int Index(SString T,SString P,int pos)
 2      {       
 3              int i,j,k;
 4              int m=strlen(P);
 5              int n=strlen(T);
 6              for(i=pos-1;i<n-m;i++)
 7              {  
 8                  for(j=0,k=i;j<m&&T[k]==P[j]; k++; j++);
 9                      if(j==m) reurn i;
10               }
11               return -1;
12      }
View Code

2.3、KMP算法實現

2.3.1、輸入和輸出
輸入:輸入主串和模式串,以及開始比較的位置
輸出:輸出模式串和主串開始匹配的起始位置,若不匹配則返回0,若匹配則返回匹配的位置。
2.3.2、關鍵數據結構與算法描述
數據結構:字符數組和整形數組
算法描述:使用KMP算法,進行字符串匹配,最大的特點和優點就是i指針不回溯。首先要找到模式串對應的next數組的值。由於找到next數組是為了更好的進行匹配,因此再進行模式串與模式串的匹配求next數組時,可以對next數組進行優化,亦即如果t[i]==t[j],在進行i++,j++後如果t[i]==t[j],則next[i]=next[j];如果不相等,next[i]=j。求出next數組之後,就是KMP算法的主體了,要是j==-1或者s[i]==t[j],i,j都要加一,要不然j=next[j];繼續進行比較,直至子串或主串結束。
2.3.2.1、求next的算法

技術分享
 1 void  get_nextval(char *t,int next[])
 2 {
 3     int i=0,j=-1;
 4     int size=strlen(t);
 5         next[0]=-1;
 6     while(i<size-1)
 7     {
 8         if(j==-1||t[i]==t[j])
 9         {
10             i++;
11             j++;
12         
13             if(t[i]==t[j])
14             {
15                 next[i]=next[j];
16             }
17             else
18                 next[i]=j;
19         }
20         else
21             j=next[j];
22     }
23 }
View Code

2.3.2.2、KMP算法主體

技術分享
 1 int   KMP(char *s,char *p,int position,int next[])
 2 {
 3     int i=position-2;//position 為比較位置,從1開始讀
 4     int j=-1;
 5     int S_SIZE=strlen(s),P_SIZE=strlen(p);
 6     while(i<S_SIZE&&j<P_SIZE)
 7     {
 8         if(j==-1||s[i]==p[j])
 9         {
10             i++;
11             j++;
12         }
13         else
14             j=next[j];
15     }
16     if(j<P_SIZE)
17         return 0;
18     else
19         return i-j+1;
20 }
View Code

2.3.3、測試與理論
1.主串:abcabdsfegabcdsdfg
模式串:abdsfe
起始位置:2,5
理論結果:4,0
2.主串:qqwerttryuriopazgdjcvjkfn
模式串:ttryu
起始位置:3,7
理論結果:6,0
技術分享技術分享

2.3.4、所有代碼

技術分享
 1 #include"stdio.h"
 2 #include"string.h"
 3 void  get_nextval(char *t,int next[])
 4 {
 5     int i=0,j=-1;
 6     int size=strlen(t);
 7         next[0]=-1;
 8     while(i<size-1)
 9     {
10         if(j==-1||t[i]==t[j])
11         {
12             i++;
13             j++;
14         
15             if(t[i]==t[j])
16             {
17                 next[i]=next[j];
18             }
19             else
20                 next[i]=j;
21         }
22         else
23             j=next[j];
24     }
25 }
26 
27 int   KMP(char *s,char *p,int position,int next[])
28 {
29     int i=position-2;//position 為比較位置,從1開始讀
30     int j=-1;
31     int S_SIZE=strlen(s),P_SIZE=strlen(p);
32     while(i<S_SIZE&&j<P_SIZE)
33     {
34         if(j==-1||s[i]==p[j])
35         {
36             i++;
37             j++;
38         }
39         else
40             j=next[j];
41     }
42     if(j<P_SIZE)
43         return 0;
44     else
45         return i-j+1;
46 }
47 
48 int  main()
49 {
50   char  s[100];
51   char  t[100];
52   int  next[100],pos=1;
53   while(1)
54   {
55 
56      printf("請輸入主串:\n");
57      scanf("%s",s);
58      printf("請輸入模式串:\n");
59      scanf("%s",t);
60      printf("請輸入開始比較的位數(默認為一)\n");
61      scanf("%d",&pos);
62 
63      get_nextval(t,next);
64      printf("開始匹配的起始位置為(若為0則不匹配)\n");
65 
66      printf("%d\n",KMP(s,t,pos,next));
67   }
68    return 0;
69 }
View Code










數據結構與算法系列研究三——字符串