串的模式匹配:BF算法

串的定义

1
2
3
4
5
#define max_Size 100
typedef struct{
char *ch;
int length;
}SString;

DF算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int index_BF(SString A,SString B){
int i = 1;int j = 1;
while(i <= A.length && j <= B.length){ //条件1:主串走到结尾。条件2:完全匹配,匹配串走到结尾
if(A.ch[i] == B.ch[j]){
i++;j++;
}
else{
i = i - (j-1) +1; //j从1到j走了j-1步,i也走了j-1步,i-(j-1)+1就回到了原位置后一个位置
j = 1;
} //依次匹配,如果相等,则继续,不相等,则回溯,重新进行下一次匹配
}
if(j >= B.length) return i - B.length; //返回匹配的第一个下标
else return 0;
}

主函数内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main(){
SString A;
SString B;
A . ch = new char[max_Size + 1];
B . ch = new char[max_Size + 1];
int i;int m;int n;
cin >> m >> n;
for(i = 1; i<=m ;i++){
cin >> A . ch[i];
}
A.length = m;
for(i = 1; i<=n ;i++){
cin >> B . ch[i];
}
B.length = n;
cout << index_BF(A,B);

}

串的模式匹配:KMP算法

求next数组

一个讲的通俗易懂的课:KMP算法

步骤:

  1. 找到ch[n]位置前的最长公共前后缀,记录串长n,(n+1)为此位置next值
  2. CH[1]的next规定为0

next值含义:
0:1号位与主串下一位比较
1:1号位与主串当前位比较
n:n号位与主串当前位比较

最长公共前后缀:现有一串ABABAB
ch[5]前最长前缀后缀为:ABABAB,next[5] = 2 + 1 = 3

ch[6]前最长前缀为:ABABAB

ch[6]前最长后缀为:ABABAB,next[6] = 3 + 1 = 4

图2.1-1 KMP算法中间略去部分一定不匹配的原因解析

求nextval数组

将ch[i]与ch[next[i]]比较。不相等,则nextval[i] = next[i];相等,则nextval[i] = next[next[i]]。

特殊矩阵压缩存储

对称矩阵/三角矩阵

以行序为主序:
$对角矩阵数组下三角部分[k]= \frac{(i-1)*(1+(i-1))}{2} + (j-1)$
上三角部分交换i,j即可

对于三角矩阵:
$下三角矩阵[k]= \frac{(i-1)*(1+(i-1))}{2} + (j-1)$

$上三角矩阵[k]= \frac{n*(n+(n-(i-1)+1))}{2} + (j-1)$

注意:三角矩阵需要额外一个存储常数c的位置
$k= \frac{n*(1+n)}{2} + 1$

稀疏矩阵:非零元素<=5%的矩阵

有序的双下标法

由三元组{(row,col,$a_{ij}$)}和矩阵维数(row,col)表示
通常在三元组下标为0的位置存放总行数,总列数,总非零元素个数等信息。

  • 优点:非零元在表中按行序有序存储,因此便于进行依行顺序处理的矩阵运算
  • 缺点:不能随机存取,若按行号取某一行中的非零元,则需从头开始查找

十字链表法

图3.2.2-1 KMP算法中间略去部分一定不匹配的原因解析

广义表

  • 取表头:取第一个元素
  • 取表尾:取除了第一个元素外其他元素组成的表
  • 求表长:所包含元素个数(最外层逗号间隔出的元素个数)
  • 求表深:最大的括号层数

    例:广义表A=(a,(b,c),(d,e,(f,g,(h)))),求表头,表尾,表长,表深,Head(Head(Tail(Head(Tail(Tail(A))))))

    1. 表头:a
    2. 表尾:((b,c),(d,e,f))
    3. 表长:3
    4. 表深:4
    5. 从后往前开括号,((b,c),(d,e,(f,g,(h)))),((d,e,(f,g,(h)))),(d,e,(f,g,(h))),((f,g,(h))),(f,g,(h)),f