基本概念:
维基百科:https://en.wikipedia.org/wiki/String_(computer_science)
百度百科:http://baike.baidu.com/link?url=YZL4T0SmYXbWBAQyUtrBMDt0pDmZRR_dDCID6BBcbL9i9y-ZmheoNT93PsXCvZbo
串(或字符串),是由零个或多个字符组成的有穷序列。含零个字符的串称为空串,用Ф表示。
串中所含字符的个数称为该串的长度(或串长)。
当且仅当两个串的长度相等并且各个对应位置上的字符都相同时,这两个串才是相等的。
一个串中任意个连续字符组成的子序列(含空串,但不含串本身)称为该串的子串。例如,“a”、“ab”、“abc”和“abcd”等都是“abcde”的子串(平凡子串不包括自身)。
例子: “abcde”有多少个平凡子串?
解: 空串数:1
含1个字符的子串数:5
含2个字符的子串数:4
含3个字符的子串数:3
含4个字符的子串数:2
共有1+2+3+4+5=15个子串。
串的存储结构:
串的顺序存储及其基本操作实现
串是一种特殊的线性表,在非紧缩格式中,它的每个结点仅由一个字符组成,因此存储串的方法也就是存储线性表的一般方法。存储串最常用的方式是采用顺序存储,即把串的字符顺序地存储在内存一片相邻的空间,这称为顺序串。
串的非紧缩格式(一个单元存放一个字符)与串的紧缩格式(一个单元存放多个字符)。
顺序存储采用一般顺序表的存储结构,其类型定义如下:
#define MaxSize 100 typedef struct { char data[MaxSize]; int len; } strtype;//[紧缩格式]
其中,ch域用来存储字符串,len域用来存储字符串的当前长度,MaxSize常量表示允许所存储字符串的最大长度。在C语言中每个字符串以' '标志结束(在这个结构体中不需要用' '标志结束,以下标为0开始存入字符)。
ASCII比较字符串
由于 "大写字母<小写字母" ,并且a<b,因此在比较时ASCII大的字母比较靠前,但要特殊考虑大小写夹杂的情况。
串的链式结构存储
链式方式存储串,即用单链表形式存储串。这称为链式串或链串。
链串中的结点类型定义:
typedef struct snode { char data; struct snode *next; } LiString;
例:在链串中,设计一个算法把最先出现的子串"ab"改为"xyz"。
解:在串s中找到最先出现的子串"ab",p指向data域值为'a'的结点,其后为data域值为'b'的结点。将它们的data域值分别改为'x'和'z',再创建一个data域值为'y'的结点,将其插入到*p之后。本例算法如下:
void Repl(LiString *&s) { iString *p=s->next,*q;int find=0; while (p->next!=NULL && find==0) { if (p->data==‘a’ && p->next->data==‘b’) /*找到*/ { p->data='x';p->next->data='z'; /*替换为xyz*/ q=(lstring *)malloc(sizeof(lstring)); q->data='y';q->next=p->next; p->next=q; find=1; } else p=p->next; } }
相关算法:
串的模式匹配----------------------------
设有主串s和子串t,子串t的定位就是要在主串s中找到一个与子串t相等的子串。通常把主串s称为目标串,把子串t称为模式串,因此定位也称作模式匹配。模式匹配成功是指在目标串s中找到一个模式串t;不成功则指目标串s中不存在模式串t。
算法一:BF算法(Brute-Force)
Brute-Force简称为BF算法,亦称简单匹配算法,其基本思路是:
从目标串s="s0s1…sn-1"的第一个字符开始和模式串t="t0t1…tm-1"中的第一个字符比较,若相等,则继续逐个比较后续字符;否则从目标串s的第二个字符开始重新与模式串t的第一个字符进行比较。依次类推,若从模式串s的第i个字符开始,每个字符依次和目标串t中的对应字符相等,则匹配成功,该算法返回i;否则,匹配失败,函数返回-1。
有2种实现方法:
//方法一 int indexpos(SqString str,SqString substr) { int i,j,k,idx=-1; for (i=0;i<str.len;i++) { for (j=i,k=0;str.data[j]==substr.data[k];j++,k++); if (k==substr.len) //注意j每次从i开始,有回溯 return(i); } return(-1); } //方法二 int index(SqString s,SqString t) { int i=0,j=0,k; while (i<s.len && j<t.len) { if (s.data[i]==t.data[j]) /*继续匹配下一个字符*/ { i++; j++; /*主串和子串依次匹配下一个字符*/ } else /*主串、子串指针回溯重新开始下一次匹配*/ { i=i-j+1; /*主串从下一个位置开始匹配*/ j=0; /*子串从头开始匹配*/ } } if (j>=t.len) k=i-t.len; /*返回匹配的第一个字符的下标*/ else k=-1; /*模式匹配不成功*/ return k; }
算法二(KMP算法):
基本概念:(转自:http://kb.cnblogs.com/page/176818/)
实现代码:
#include<stdio.h> #include<string.h> void makeNext(const char P[],int next[]) { int q,k; int m = strlen(P); next[0] = 0; for (q = 1,k = 0; q < m; ++q) { while(k > 0 && P[q] != P[k]) k = next[k-1]; if (P[q] == P[k]) { k++; } next[q] = k; } } int kmp(const char T[],const char P[],int next[]) { int n,m; int i,q; n = strlen(T); m = strlen(P); makeNext(P,next); for (i = 0,q = 0; i < n; ++i) { while(q > 0 && P[q] != T[i]) q = next[q-1]; if (P[q] == T[i]) { q++; } if (q == m) { printf("Pattern occurs with shift:%d ",(i-m+1)); } } } int main() { int i; int next[20]={0}; char T[] = "ababxbababcadfdsss"; char P[] = "abcdabd"; printf("%s ",T); printf("%s ",P ); // makeNext(P,next); kmp(T,P,next); for (i = 0; i < strlen(P); ++i) { printf("%d ",next[i]); } printf(" "); return 0; }