串(string)(或字符串):由零个或多个字符组成的有限序列,记为 s = “a_1 a_2 ··· a_n” (n ≥ 0)
子串:串中任意连续的字符组成的子序列
主串:包含子串的串
位置:字符在序列中的序号
子串在主串中的位置:以子串的第一个字符在主串中的位置来表示
a = "abcd";
b = "ABCD";
c = "abcdABCD";
d = "abcd ABCD";
// a 和 b 都是 c 和 d 的子串
// a 在 c 和 d 中的位置都是 1
// b 在 c 中的位置是 5
// b 在 d 中的位置是 6
相等:两个串的值相等
空格串(blank string):由一个或多个空格组成的串
#define MAXLEN 10
typedef struct {
char ch[MAXLEN + 1]; // 存储串的一维数组
int length; // 串的当前长度
} SString;
typedef struct {
char *ch; // 若为非空串,则按串长分配存储区,否则 ch 为 NULL
int length; // 串的当前长度
} HString;
#define CHUNKSIZE 5
typedef struct Chunk {
char ch[CHUNKSIZE];
struct Chunk *next;
} Chunk;
typedef struct {
Chunk *head; // 串的头指针
Chunk *tail; // 串的尾指针
int length; // 串的当前长度
} LString;
模式匹配 / 串匹配:子串的定位运算
补:以下代码均使用定长顺序存储结构
void Index_BF(SString S, SString T, int index) {
int i = index;
int j = 0;
while (i < S.length && j < T.length )
{
if (S.ch[i] == T.ch[j])
{
i++;
j++;
}
else {
i = ++index;
j = 0;
}
}
if (j > T.length - 1)
{
printf("Index_BF Success\n");
printf("Index from %d to %d\n", index, index + j - 1);
}
else
{
printf("Error\n");
}
}
最好情况:每次不成功的匹配都发生在模式串的第一个字符与主串中相应字符的比较
S = "aaaaaba";
T = "ba";
设主串长度为 n ,子串长度为 m ,匹配成功概率处处相等,则平均比较次数为
∑ i = 1 n − m + 1 p n ( i − 1 + m ) = 1 n − m + 1 ∑ i = 1 n − m + 1 i − 1 + m = 1 2 ( n + m ) \sum_{i=1}^{n-m+1}{p_n(i-1+m)} = \frac{1}{n-m+1}\sum_{i=1}^{n-m+1}{i-1+m} = \frac{1}{2}(n+m) i=1∑n−m+1pn(i−1+m)=n−m+11i=1∑n−m+1i−1+m=21(n+m)
因此,最好情况下的平均时间复杂度为 O(n+m)
void Index_KMP(SString S, SString T) {
int next[10];
// 根据模式串 T,初始化 next 数组
Next(T, next);
int i = 1;
int j = 1;
while (i <= S.length && j <= T.length)
{
// j==0 :模式串的第一个字符就和当前测试的字符不相等
// S[i-1] == T.ch[j-1] :如果对应位置字符相等,两种情况下,指向当前测试的两个指针下标i和j都向后移
if (j == 0 || S.ch[i-1] == T.ch[j-1])
{
i++;
j++;
}
else
{
// 如果测试的两个字符不相等,i不动,j变为当前测试字符串的next值
j = next[j];
}
}
if (j > T.length)
{
printf("Success\n");
}
else
{
printf("Error\n");
}
}
void Next(SString T, int* next) {
int i = 1;
next[1] = 0;
int j = 0;
while (i < T.length)
{
if (j == 0 || T.ch[i-1] == T.ch[j-1])
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j];
}
}
}
#include
#include
#define MAXLEN 10
void InitString(SString);
void AssignString(SString);
void Index_BF(SString, SString);
void Index_KMP(SString, SString);
void Next(SString);
typedef struct {
char ch[MAXLEN + 1];
int length;
} SString;
int main() {
SString S1;
SString S2;
char c1[10] = "ababcABC";
char c2[5] = "abc";
InitString(&S1);
InitString(&S2);
printf("****************\n");
AssignString(&S1, c1);
AssignString(&S2, c2);
printf("****************\n");
Index_BF(S1, S2, 0);
printf("****************\n");
Index_KMP(S1, S2);
printf("****************\n");
}
void InitString(SString* S) {
S->ch[0] = '\0';
S->length = 0;
printf("Init Success\n");
}
void AssignString(SString* S, char* C) {
int len = S->length = strlen(C);
for (int i = 0; i < len; i++)
{
S->ch[i] = C[i];
}
S->ch[len] = '\0';
printf("Assign Success\n");
}
void Index_BF(SString S, SString T, int index) {
int i = index;
int j = 0;
while (i < S.length && j < T.length )
{
if (S.ch[i] == T.ch[j])
{
i++;
j++;
}
else {
i = ++index;
j = 0;
}
}
if (j > T.length - 1)
{
printf("Index_BF Success\n");
printf("Index from %d to %d\n", index, index + j - 1);
}
else
{
printf("Error\n");
}
}
void Index_KMP(SString S, SString T) {
int next[10];
// 根据模式串 T,初始化 next 数组
Next(T, next);
int i = 1;
int j = 1;
while (i <= S.length && j <= T.length)
{
// j==0 :模式串的第一个字符就和当前测试的字符不相等
// S[i-1] == T.ch[j-1] :如果对应位置字符相等,两种情况下,指向当前测试的两个指针下标i和j都向后移
if (j == 0 || S.ch[i - 1] == T.ch[j - 1])
{
i++;
j++;
}
else
{
// 如果测试的两个字符不相等,i不动,j变为当前测试字符串的next值
j = next[j];
}
}
if (j > T.length)
{
printf("Index_KMP Success\n");
}
else
{
printf("Error\n");
}
}
void Next(SString T, int* next) {
int i = 1;
next[1] = 0;
int j = 0;
while (i < T.length)
{
if (j == 0 || T.ch[i - 1] == T.ch[j - 1])
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j];
}
}
}
数组一般不做插入或删除操作,因此,采用顺序存储结构
随机存取结构
假设每个数据元素站 L 个存储单元,则二维数组 A[0 ··· m-1, 0 ··· n-1](下标从 0 开始,共有 m 行 n 列)中任一元素 a_ij 的存储位置可由下式确定
L O C ( i , j ) = L O C ( 0 , 0 ) + ( n ∗ i + j ) L LOC(i, j) = LOC(0, 0) + (n*i+j)L LOC(i,j)=LOC(0,0)+(n∗i+j)L
LOC(i, j) 是 a_ij 的存储位置,LOC(0, 0) 是 a_00 的存储位置
n 维数组 A[0 ··· b_1-1, 0 ··· b_2-1, ··· , 0 ··· b_n-1] 的数据元素存储位置的计算公式
L O C ( j 1 , j 2 , ⋅ ⋅ ⋅ , j n ) = L O C ( 0 , 0 , ⋅ ⋅ ⋅ , 0 ) + ( b 2 ∗ ⋅ ⋅ ⋅ ∗ b n ∗ j 1 + b 3 ∗ ⋅ ⋅ ⋅ ∗ b n ∗ j 2 + ⋅ ⋅ ⋅ + b n ∗ j n − 1 + j n ) L LOC(j_1, j_2, ···, j_n) = LOC(0,0,···,0)+(b_2*···*b_n*j_1 + b_3*···*b_n*j_2 + ··· + b_n*j_{n-1} + j_n)L LOC(j1,j2,⋅⋅⋅,jn)=LOC(0,0,⋅⋅⋅,0)+(b2∗⋅⋅⋅∗bn∗j1+b3∗⋅⋅⋅∗bn∗j2+⋅⋅⋅+bn∗jn−1+jn)L
= L O C ( 0 , 0 , ⋅ ⋅ ⋅ , 0 ) + ( ∑ i = 1 n − 1 j i ∏ k = i + 1 n b k + j n ) L = LOC(0,0,···,0)+(\sum_{i=1}^{n-1}{j_i}\prod_{k=i+1}^{n}{b_k}+j_n)L =LOC(0,0,⋅⋅⋅,0)+(i=1∑n−1jik=i+1∏nbk+jn)L
缩写成
L O C ( j 1 , j 2 , ⋅ ⋅ ⋅ , j n ) = L O C ( 0 , 0 , ⋅ ⋅ ⋅ , 0 ) + ∑ i = 1 n c i j i LOC(j_1, j_2, ···, j_n) = LOC(0,0,···,0)+\sum_{i=1}^{n}{c_ij_i} LOC(j1,j2,⋅⋅⋅,jn)=LOC(0,0,⋅⋅⋅,0)+i=1∑nciji
c_n = L ,c_{i-1} = b_i * c_i ,1 < i ≤ n
a_ij = a_ji ,1 ≤ i ,j ≤ n
存储下三角(包括对角线)中的元
假设 sa [n(n+1)/2] 作为 n 阶对称矩阵 A 的存储结构
sa [k] 和矩阵元 a_ij 之间的对应关系为
k = { i ( i − 1 ) 2 + j − 1 当 i ≥ j j ( j − 1 ) 2 + i − 1 当 i < j k=\begin{cases} \frac{i(i-1)}{2} + j - 1 \quad 当 i ≥ j \\ \frac{j(j-1)}{2} + i - 1 \quad 当 i < j\end{cases} k={2i(i−1)+j−1当i≥j2j(j−1)+i−1当i<j
推导过程
对称矩阵一共具有的元素数量为
n ∗ ( n + 1 ) 2 \frac{n*(n+1)}{2} 2n∗(n+1)
下标范围为
[ 0 , n ∗ ( n + 1 ) 2 − 1 ] [0, \frac{n*(n+1)}{2} - 1] [0,2n∗(n+1)−1]
a_nn 的下标为
n ∗ ( n + 1 ) 2 − 1 \frac{n*(n+1)}{2} - 1 2n∗(n+1)−1
a_n1 的下标为
n ∗ ( n + 1 ) 2 − ( n − 1 ) − 1 = n ∗ ( n − 1 ) 2 \frac{n*(n+1)}{2} - (n - 1) - 1= \frac{n*(n-1)}{2} 2n∗(n+1)−(n−1)−1=2n∗(n−1)
a_nj 的下标为
n ∗ ( n − 1 ) 2 + j − 1 \frac{n*(n-1)}{2} + j - 1 2n∗(n−1)+j−1
a_ij 的下标为
i ∗ ( i − 1 ) 2 + j − 1 \frac{i*(i-1)}{2} + j - 1 2i∗(i−1)+j−1
广义表是线性表的推广,也称为列表
一般记作 LS = (a_1, a_2, ··· , a_n)
3 个重要结论
2 个重要的运算
AB = (a, b);
C = (c);
ABC = (AB, C);
GetHead(ABC) == AB;
GetTail(ABC) == (C);
GetHead(AB) == a;
GetTail(AB) == (b);
GetHead(C) == c;
GetTail(C) == ();
typedef enum {ATOM, LIST} ElemTag; // 枚举
// ATOM == 0 : 原子
// ATOM == 1 : 子表
typedef struct GLNode {
ElemTag tag; // 用于区分原子结点和表结点
union { // 联合
AtomType atom; // 原子结点值域,用户自行定义
struct { // 表结点的指针域
struct GLNode *hp; // 表头
struct GLNode *tp; // 表尾
} ptr;
};
} *Glist;