【数据结构】串与数组
Problem A 三元组顺序表表示的稀疏矩阵转置运算Ⅰ
题目
7-1 三元组顺序表表示的稀疏矩阵转置运算Ⅰ
全屏浏览题目切换布局
作者 王东
单位 贵州师范学院
三元组顺序表表示的稀疏矩阵转置。
输入格式:
输入第1行为矩阵行数m、列数n及非零元素个数t。
按行优先顺序依次输入t行,每行3个数,分别表示非零元素的行标、列标和值。
输出格式:
输出转置后的三元组顺序表结果,每行输出非零元素的行标、列标和值,行标、列标和值之间用空格分隔,共t行。
输入样例1:
3 4 3
0 1 -5
1 0 1
2 2 2
输出样例1:
0 1 1
1 0 -5
2 2 2
思路
使用三元组表示稀疏矩阵中的非零元素,进而创建一个三元组数组data[]来存储稀疏矩阵中的所有非零元素。**预先确定矩阵M中每一列(即T中的每一行)的第一个非零元在T的data[]数组中的位置,则在对M的data[]数组中的三元组依次作转置时,能够直接把该非零元素放到T的data[]数组中的恰当位置。**最后输出结果即可。
代码
#include <iostream>
using namespace std;
typedef int ElemType;
#define MAXSIZE 100 // 非零元个数的最大值
struct Triple {
int i, j; // 行下标和列下标
ElemType e; //非零元素值
};
struct TSMatrix {
Triple data[MAXSIZE]; // 非零元三元组表,data[0]未用
int rows, columns, num; // 矩阵行数、列数和非零元个数
};
/// @brief 创建稀疏矩阵M
/// @param M
void CreateSMatrix(TSMatrix &M) {
int i, m, n;
ElemType e;
scanf("%d %d %d", &M.rows, &M.columns, &M.num);
for (i = 0; i < M.num; ++i) {
scanf("%d %d %d", &m, &n, &e);
M.data[i].i = m;
M.data[i].j = n;
M.data[i].e = e;
}
}
/// @brief 输出稀疏矩阵M
/// @param M
void PrintSMatrix(TSMatrix M) {
for (int ind = 1; ind <= M.num; ++ind) {
printf("%d %d %d\n", M.data[ind].i, M.data[ind].j, M.data[ind].e);
}
}
/// @brief 快速求稀疏矩阵M的转置矩阵T
/// @param M
/// @param T
void FastTransposeSMatrix(TSMatrix M, TSMatrix &T) {
int p = 0, q = 0, t = 0, col = 0;
int num[M.columns]; // num[col]表示矩阵M中第col列中非零元的个数
int cpot[M.columns]; // cpot[col]指示M中第col列的第一个非零元在b.data中的位置
T.rows = M.columns;
T.columns = M.rows;
T.num = M.num;
if (T.num) {
// 设初值
for (col = 0; col < M.columns; ++col) {
num[col] = 0;
cpot[col] = 0;
}
cpot[0] = 1;
// 求M中每一列含非零元元素的个数
for (t = 0; t < M.num; ++t) {
++num[M.data[t].j];
}
// 求第col列中第一个非零元在T.data中的序号
for (col = 1; col < M.columns; ++col) {
cpot[col] = cpot[col - 1] + num[col - 1];
}
for (p = 0; p < M.num; ++p) {
col = M.data[p].j;
q = cpot[col];
T.data[q].i = M.data[p].j;
T.data[q].j = M.data[p].i;
T.data[q].e = M.data[p].e;
++cpot[col];
}
}
}
TSMatrix S, T;
int main() {
CreateSMatrix(S);
FastTransposeSMatrix(S, T);
PrintSMatrix(T);
}
Problem B 三元组顺序表表示的稀疏矩阵加法
题目
7-2 三元组顺序表表示的稀疏矩阵加法
全屏浏览题目切换布局
作者 王东
单位 贵州师范学院
三元组顺序表表示的稀疏矩阵加法。
输入格式:
输入第1行为两个同型矩阵的行数m、列数n,矩阵A的非零元素个数t1,矩阵B的非零元素个数t2。
按行优先顺序依次输入矩阵A三元组数据,共t1行,每行3个数,分别表示非零元素的行标、列标和值。
按行优先顺序依次输入矩阵B三元组数据,共t2行,每行3个数,分别表示非零元素的行标、列标和值。
输出格式:
输出第1行为相加后矩阵行数m、列数n及非零元素个数t。
输出t行相加后的三元组顺序表结果,每行输出非零元素的行标、列标和值,每行数据之间用空格分隔。
输入样例1:
4 4 3 4
0 1 -5
1 3 1
2 2 1
0 1 3
1 3 -1
3 0 5
3 3 7
输出样例1:
4 4 4
0 1 -2
2 2 1
3 0 5
3 3 7
思路
使用三元组表示稀疏矩阵中的非零元素,进而创建一个三元组数组data[]来存储稀疏矩阵中的所有非零元素。对非零元素的坐标进行对比,如果坐标相同说明值要相加,否则直接赋值给矩阵Q。考虑到两个矩阵M和N的非零元素个数可能不相同,那么直接将剩余元素赋值给矩阵Q即可。输出时要注意忽略零元素。
代码
#include <bits/stdc++.h>
using namespace std;
typedef int ElemType;
#define MAXSIZE 100 // 非零元个数的最大值
struct Triple
{
int i, j; // 行下标和列下标
ElemType e; //非零元素值
};
struct TSMatrix
{
Triple data[MAXSIZE + 1]; // 非零元三元组表,data[0]未用
int rows, columns, num; // 矩阵行数、列数和非零元个数
};
/// @brief 用于比较c1和c2
/// @param c1
/// @param c2
/// @return
int comp(int c1, int c2)
{
if (c1 < c2)
return 1;
else if (c1 == c2)
return 0;
else
return -1;
}
/// @brief 创建稀疏矩阵A, B
/// @param M
void CreateSMatrix(TSMatrix &A, TSMatrix &B)
{
int i, m, n;
ElemType e;
scanf("%d %d %d %d", &A.rows, &A.columns, &A.num, &B.num);
B.rows = A.rows;
B.columns = B.columns;
for (i = 0; i < A.num; ++i)
{
scanf("%d %d %d", &m, &n, &e);
A.data[i].i = m;
A.data[i].j = n;
A.data[i].e = e;
}
for (i = 0; i < B.num; ++i)
{
scanf("%d %d %d", &m, &n, &e);
B.data[i].i = m;
B.data[i].j = n;
B.data[i].e = e;
}
}
/// @brief 求稀疏矩阵的和Q=M+N
/// @param M
/// @param N
/// @param Q
void AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
{
Triple *Mp, *Me, *Np, *Ne, *Qh, *Qe;
Q.rows = M.rows;
Q.columns = M.columns;
Mp = &M.data[0]; // Mp的初值指向矩阵M的非零元素首地址
Np = &N.data[0]; // Np的初值指向矩阵N的非零元素首地址
Me = &M.data[M.num]; // Me指向矩阵M的非零元素尾地址
Ne = &N.data[N.num]; // Ne指向矩阵N的非零元素尾地址
Qh = Qe = Q.data; // Qh、Qe的初值指向矩阵Q的非零元素首地址的前一地址
while (Mp <= Me && Np <= Ne)
{
Qe++;
switch (comp(Mp->i, Np->i))
{
case 1:
*Qe = *Mp;
Mp++;
break;
case 0:
switch (comp(Mp->j, Np->j)) // M、N矩阵当前非零元素的行相等,继续比较列
{
case 1:
*Qe = *Mp;
Mp++;
break;
case 0:
*Qe = *Mp;
Qe->e += Np->e;
if (!Qe->e) // 元素值为0,不存入压缩矩阵
Qe--;
Mp++;
Np++;
break;
case -1:
*Qe = *Np;
Np++;
}
break;
case -1:
*Qe = *Np;
Np++;
}
}
if (Mp > Me) // 矩阵M的元素全部处理完毕
while (Np <= Ne)
{
Qe++;
*Qe = *Np;
Np++;
}
if (Np > Ne) // 矩阵N的元素全部处理完毕
while (Mp <= Me)
{
Qe++;
*Qe = *Mp;
Mp++;
}
Q.num = Qe - Qh; // 矩阵Q的非零元素个数
}
/// @brief 输出稀疏矩阵M
/// @param M
void PrintSMatrix(TSMatrix M)
{
int count = 0; // 计算零元素的个数,在输出时忽略之
for (int ind = 1; ind <= M.num; ++ind)
{
if (M.data[ind].e == 0) {
count++;
}
}
printf("%d %d %d\n", M.rows, M.columns, M.num - count);
for (int ind = 1; ind <= M.num; ++ind)
{
if (M.data[ind].e == 0)
{
continue;
}
printf("%d %d %d\n", M.data[ind].i, M.data[ind].j, M.data[ind].e);
}
}
TSMatrix A, B, Q;
int main()
{
CreateSMatrix(A, B);
AddSMatrix(A, B, Q);
PrintSMatrix(Q);
}
Problem C 串的模式匹配
题目
7-3 串的模式匹配
全屏浏览题目切换布局
作者 陈越
单位 浙江大学
给定两个由英文字母组成的字符串 String 和 Pattern,要求找到 Pattern 在 String 中第一次出现的位置,并将此位置后的 String 的子串输出。如果找不到,则输出“Not Found”。
本题旨在测试各种不同的匹配算法在各种数据情况下的表现。各组测试数据特点如下:
- 数据0:小规模字符串,测试基本正确性;
- 数据1:随机数据,String 长度为 105,Pattern 长度为 10;
- 数据2:随机数据,String 长度为 105,Pattern 长度为 102;
- 数据3:随机数据,String 长度为 105,Pattern 长度为 103;
- 数据4:随机数据,String 长度为 105,Pattern 长度为 104;
- 数据5:String 长度为 106,Pattern 长度为 105;测试尾字符不匹配的情形;
- 数据6:String 长度为 106,Pattern 长度为 105;测试首字符不匹配的情形。
输入格式:
输入第一行给出 String,为由英文字母组成的、长度不超过 106 的字符串。第二行给出一个正整数 N(≤10),为待匹配的模式串的个数。随后 N 行,每行给出一个 Pattern,为由英文字母组成的、长度不超过 105 的字符串。每个字符串都非空,以回车结束。
输出格式:
对每个 Pattern,按照题面要求输出匹配结果。
输入样例:
abcabcabcabcacabxy
3
abcabcacab
cabcabcd
abcabcabcabcacabxyz
输出样例:
abcabcacabxy
Not Found
Not Found
思路
KMP算法,通过利用模式串pattern的信息,减少无效重复匹配的次数进而降低时间复杂度。
代码
#include <bits/stdc++.h>
using namespace std;
typedef char SString;
/// @brief 求模式串T的next函数值并存入数组next
/// @param T
/// @param next
int* get_next(SString *T) {
int len = strlen(T);
int *next = (int *)malloc(sizeof(int) * len);
int i = 0, j = -1;
next[0] = -1;
while (i < len - 1) {
if (j == -1 || T[i] == T[j]) {
++i;
++j;
next[i] = j;
} else {
j = next[j];
}
}
return next;
} // get_next
/// @brief 利用模式串T的next函数求T在主串S中第pos个字符之后的位置的KMP算法
/// @param S 主串
/// @param T 模式串
/// @param pos 开始位置
/// @param next next数组
/// @return 第一次出现的位置
int Index_KMP(SString *S, SString *T, int *next) {
int i = 0, j = 0;
int lenS = strlen(S);
int lenT = strlen(T);
while (i < lenS && j < lenT) {
// 继续比较后继字符
if (j == -1 || S[i] == T[j]) {
++i;
++j;
} else { // 匹配成功
j = next[j];
}
}
if (j == lenT) { // 匹配成功
return i - lenT;
} else {
return -1;
}
} // Index_KMP
/// @brief 输出S中index位置后的子串
/// @param S
/// @param index
void SubStrPrint(SString *S, int index) {
int i = index;
while (S[i]) {
cout << S[i];
i++;
}
printf("\n");
} // SubStrPrint
int main() {
SString *S, *T;
S = (SString *)malloc(sizeof(SString) * 1e6);
T = (SString *)malloc(sizeof(SString) * 1e5);
int num;
cin >> S;
cin >> num;
for (int i = 1; i <= num; i++) {
cin >> T;
int *next = get_next(T);
int index = Index_KMP(S, T, next);
if (index == -1) {
cout << "Not Found" << endl;
} else {
SubStrPrint(S, index);
}
}
return 0;
}