如何迭代获取特定的结构元素并将它们存储到 C 中的二维数组中?
How to iteratively take specific struct elements and store them into a 2D array in C?
所以我有一个二维字符串数组,如下所示:
char str[12][100] = {
"a = 2.b, 1.d",
"b = 2.a, 1.e, 2.c",
"c = 2.b, 1.f",
"d = 1.a, 1.g",
"e = 1.h, 1.b",
"f = 1.i, 1.c",
"g = 1.j, 1.d",
"h = 1.k, 1.e",
"i = 1.l, 1.f",
"j = 1.g, 2.k",
"k = 2.j, 1.h, 2.l",
"l = 2.k, 1.i"
};
这些字符串表示地图布局,其中点 "a" 连接到点 "b" 和 "d" 并且连接的点之间存在关联的距离(或权重)指向"a"。以下是从所有这些字符串转换后的布局:
a--(2)--b--(2)--c
| | |
(1) (1) (1)
| | |
d e f
| | |
(1) (1) (1)
| | |
g h i
| | |
(1) (1) (1)
| | |
j--(2)--k--(2)--l
我有一个结构,像这样:
struct stopPoints {
int weights[10];
char connectingPoints[10];
};
我已经成功获取了每个字符串,并将每个字母和数字放入其自己的结构中。我通过创建这样的结构数组来做到这一点: struct stopPoints store[26];
然后我通过添加每个字符串的适当元素来迭代地填充每个结构。例如,对于我的第一个字符串 "a = 2.b, 1.d"
,我将字母 "a" "b" 和 "d" 分别放入 store[0].connectingPoints[0], store[0].connectingPoints[1], and store[0].connectingPoints[2],
中。所以像这样:
store[0].connectingPoints[0] = 'a';
store[0].connectingPoints[1] = 'b';
store[0].connectingPoints[2] = 'd';
我也将两个数字放入结构的 "weights" 元素中,如下所示:
store[0].weights[0] = 2;
store[0].weights[1] = 1;
我已经对所有 12 个字符串进行了测试,一切就绪。
现在,我想用我拥有的这些字符串创建一个邻接矩阵。邻接矩阵应该是这样的:
0 2 0 1 0 0 0 0 0 0 0 0
2 0 2 0 1 0 0 0 0 0 0 0
0 2 0 0 0 1 0 0 0 0 0 0
1 0 0 0 0 0 1 0 0 0 0 0
0 1 0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0 0 1 0 0
0 0 0 0 1 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0 0 0 0 1
0 0 0 0 0 0 1 0 0 0 2 0
0 0 0 0 0 0 0 1 0 2 0 2
0 0 0 0 0 0 0 0 1 0 2 0
再解释一下,第一行[0](代表点"a")在[0][1]索引中包含2(代表到点"b"的距离)和在[0][3]索引中包含1(表示到点"d"的距离)。
因此,第二行 [1] 在 [1][0] 和 [1][2] 索引中包含一个 2,因为点 b 连接到点 a 和点 c 以及索引 [1][ 5] 包含一个 1 因为点 b 也连接到点 e。如您所见,每一行和每一列实际上按顺序代表字母 a-l(0=a、1=b、2=c 等)。
我已经初始化并填充了一个全 0 的 12x12 数组。我似乎无法将我的权重值正确填充到相应的索引中。这是我许多失败的方法之一:
int row2, col2, ugh=1;
for (row2 = 0; row2 < 12; row2++){
for (col2 = 0; col2 < 12; col2++){
while(store[row2].connectingPoints[ugh] != NULL){
adjmatrix[row2][col2] = store[row2].weights[col2];
ugh++;
}
}
}
以下是将前两个字符串硬编码到邻接矩阵中的方法:
//a=2b, 1d;
adjmatrix[0][0] = 0; //point a
adjmatrix[0][1] = store[0].weights[0];
adjmatrix[0][3] = store[0].weights[1];
//b=2a, 2c, 1e;
adjmatrix[1][0] = store[1].weights[0];
adjmatrix[1][1] = 0; //point b
adjmatrix[1][2] = store[1].weights[1];
adjmatrix[1][4] = store[1].weights[2];
我只是不知道如何迭代地执行此操作。任何帮助将不胜感激。
从 char[][]
转换为 adjmatrix
可以通过一些字符串解析来完成,如下面的代码所示。
int adjmatrix[26][26] = {0}; //assuming 26 possible points (from question "struct stopPoints store[26]")
int i,j,k = 0;
int n = 12;
for (i = 0; i < n; ++i) {
int l = strlen(str[i]);
for (j = 0; j < l; ++j) {
if (str[i][j] == '.') {
adjmatrix[str[i][0] - 'a'][str[i][j+1] - 'a'] = getWeight(str[i], j);
// (char) - 'a', gives an integer value for the small case alphabets (a->1, b->2, c->3 ...)
}
}
}
getWeight()
int getWeight(char s[], int j) {
// returns the integer on left of '.' from the string
int w = 0,i = 0;
int m = 1;
for (i = j-1; s[i] >= '0' && s[i] <= '9'; --i) {
w += (s[i] - '0')*m;
m *= 10;
}
return w;
}
如果您真的需要使用该结构,那么您可以通过使每个商店的 weights
数量等于 connectingPoints
数量来简化它。即,如果您要添加 store[0].connectingPoints[0] = 'a';
,则权重为
store[0].weights[0] = 0; // weight of point a to point a
store[0].weights[1] = 2; // weight of point a to point b
store[0].weights[2] = 1; // weight of point a to point d
另一个例如:"c = 2.b, 1.f",
(不确定代码中 connectingPoints
的顺序是什么,但请注意基于索引的点和权重的一对一映射)
store[2].connectingPoints[0] = 'b';
store[2].connectingPoints[1] = 'c';
store[2].connectingPoints[2] = 'f';
store[2].weights[0] = 2;
store[2].weights[1] = 0;
store[2].weights[2] = 1;
如果你知道没有自循环,你可以避免将它们存储在 connectedPoints
中并进一步添加相应的条目到 weights
.
在这种情况下,您可以使用这样的循环构建 adjmatrix
struct stopPoints store[26];
for (i = 0; i < n; ++i) {
int l = strlen(store[i].connectingPoints);
for (j = 0; j < l; ++j) {
adjmatrix[str[i][0] - 'a'][store[i].connectingPoints[j] - 'a'] = store[i].weights[j];
}
}
字符到整数的转换
您可以找到 ASCII table here 的副本。您应该将此页面添加为书签,因为如果您花很多时间编程,您会经常参考它(每年两次,比如说,持续 30 多年)。
了解 ASCII 码(Latin1、Unicode 等的子集)的重要一点是数字、大写字母和小写字母位于三个连续的组中,按升序排列。
即'0'的代码比'1'的代码少1,以此类推,直到'9'。 'A'..'Z' 和 'a'..'z'.
也是如此
因此您可以通过简单的减法将字符值转换为索引值:
int ch0 = 'a' - 'a'; // == 0
int ch1 = 'b' - 'a'; // == 1
int ch4 = 'e' - 'a'; // == 4
如果您有一个(小写,ASCII)字符值,并从中减去 'a',您将得到一个 0..25.
范围内的整数值
这意味着您可以使用该公式计算邻接矩阵的两个索引值:
#define MAX_CONN 10
#define NUM_STORES 12
#define STORE_INDEX(ch) ((ch) - 'a')
#define FIRST_STORE 'a'
#define END_STORES (FIRST_STORE + NUM_STORES)
#define MAX_WEIGHT 100
// NOTE: I'm ignoring return type, and adjmatrix's
// lifetime, in favor of just putting this code all
// in one place. You'll have to figure out the rest.
void build_adj() {
struct stopPoints store[NUM_STORES]; // Values?
int adjmatrix[NUM_STORES][NUM_STORES] = {0};
for (st = FIRST_STORE; st < END_STORES; ++st) {
int row = STORE_INDEX(st);
// Set default weights: MAX_WEIGHT or 0 (for self)
for (i = 0; i < NUM_STORES; ++i) {
adjmatrix[row][i] = MAX_WEIGHT;
}
adjmatrix[row][row] = 0;
// Install parsed weights for this row
for (iconn = 0; iconn < MAX_CONN; ++iconn) {
// NB: setting connectingPoints[x] to '[=11=]' invalidates connection.
char st2 = store[row].connectingPoints[iconn];
if (st2 != '[=11=]') {
adjmatrix[row][STORE_INDEX(st2)] = store[row].weights[iconn];
// FIXME: Maybe set reflexive weight? a->b, b->a?
}
}
}
}
Struct/Array反转
现在你有一个包含一对数组的结构数组。我建议您将其反转,并构建一个结构数组,其中包含一个包含具有两个数据元素的结构的数组。
像这样:
typedef struct Connection {
char conn_target;
int conn_weight;
} Connection;
typedef struct StopPoints {
Connection sp_connections[MAX_CONN];
} StopPoints;
然后你有:
StopPoints store[MAX_STORES];
// most code stays the same
st2 = store[row].sp_connections[iconn].conn_target;
// ...
adjmatrix[row][STORE_INDEX(st2)] = store[row].sp_connections[iconn].conn_weight;
这样做的好处是概念上的:连接目标和权重捆绑在同一个结构中。它使这更容易思考,也更容易转换为使用指针 ;-)。
另一方面,由于结构填充,它会占用更多内存。但我认为你现在不关心这个。
所以我有一个二维字符串数组,如下所示:
char str[12][100] = {
"a = 2.b, 1.d",
"b = 2.a, 1.e, 2.c",
"c = 2.b, 1.f",
"d = 1.a, 1.g",
"e = 1.h, 1.b",
"f = 1.i, 1.c",
"g = 1.j, 1.d",
"h = 1.k, 1.e",
"i = 1.l, 1.f",
"j = 1.g, 2.k",
"k = 2.j, 1.h, 2.l",
"l = 2.k, 1.i"
};
这些字符串表示地图布局,其中点 "a" 连接到点 "b" 和 "d" 并且连接的点之间存在关联的距离(或权重)指向"a"。以下是从所有这些字符串转换后的布局:
a--(2)--b--(2)--c
| | |
(1) (1) (1)
| | |
d e f
| | |
(1) (1) (1)
| | |
g h i
| | |
(1) (1) (1)
| | |
j--(2)--k--(2)--l
我有一个结构,像这样:
struct stopPoints {
int weights[10];
char connectingPoints[10];
};
我已经成功获取了每个字符串,并将每个字母和数字放入其自己的结构中。我通过创建这样的结构数组来做到这一点: struct stopPoints store[26];
然后我通过添加每个字符串的适当元素来迭代地填充每个结构。例如,对于我的第一个字符串 "a = 2.b, 1.d"
,我将字母 "a" "b" 和 "d" 分别放入 store[0].connectingPoints[0], store[0].connectingPoints[1], and store[0].connectingPoints[2],
中。所以像这样:
store[0].connectingPoints[0] = 'a';
store[0].connectingPoints[1] = 'b';
store[0].connectingPoints[2] = 'd';
我也将两个数字放入结构的 "weights" 元素中,如下所示:
store[0].weights[0] = 2;
store[0].weights[1] = 1;
我已经对所有 12 个字符串进行了测试,一切就绪。
现在,我想用我拥有的这些字符串创建一个邻接矩阵。邻接矩阵应该是这样的:
0 2 0 1 0 0 0 0 0 0 0 0
2 0 2 0 1 0 0 0 0 0 0 0
0 2 0 0 0 1 0 0 0 0 0 0
1 0 0 0 0 0 1 0 0 0 0 0
0 1 0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0 0 1 0 0
0 0 0 0 1 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0 0 0 0 1
0 0 0 0 0 0 1 0 0 0 2 0
0 0 0 0 0 0 0 1 0 2 0 2
0 0 0 0 0 0 0 0 1 0 2 0
再解释一下,第一行[0](代表点"a")在[0][1]索引中包含2(代表到点"b"的距离)和在[0][3]索引中包含1(表示到点"d"的距离)。
因此,第二行 [1] 在 [1][0] 和 [1][2] 索引中包含一个 2,因为点 b 连接到点 a 和点 c 以及索引 [1][ 5] 包含一个 1 因为点 b 也连接到点 e。如您所见,每一行和每一列实际上按顺序代表字母 a-l(0=a、1=b、2=c 等)。
我已经初始化并填充了一个全 0 的 12x12 数组。我似乎无法将我的权重值正确填充到相应的索引中。这是我许多失败的方法之一:
int row2, col2, ugh=1;
for (row2 = 0; row2 < 12; row2++){
for (col2 = 0; col2 < 12; col2++){
while(store[row2].connectingPoints[ugh] != NULL){
adjmatrix[row2][col2] = store[row2].weights[col2];
ugh++;
}
}
}
以下是将前两个字符串硬编码到邻接矩阵中的方法:
//a=2b, 1d;
adjmatrix[0][0] = 0; //point a
adjmatrix[0][1] = store[0].weights[0];
adjmatrix[0][3] = store[0].weights[1];
//b=2a, 2c, 1e;
adjmatrix[1][0] = store[1].weights[0];
adjmatrix[1][1] = 0; //point b
adjmatrix[1][2] = store[1].weights[1];
adjmatrix[1][4] = store[1].weights[2];
我只是不知道如何迭代地执行此操作。任何帮助将不胜感激。
从 char[][]
转换为 adjmatrix
可以通过一些字符串解析来完成,如下面的代码所示。
int adjmatrix[26][26] = {0}; //assuming 26 possible points (from question "struct stopPoints store[26]")
int i,j,k = 0;
int n = 12;
for (i = 0; i < n; ++i) {
int l = strlen(str[i]);
for (j = 0; j < l; ++j) {
if (str[i][j] == '.') {
adjmatrix[str[i][0] - 'a'][str[i][j+1] - 'a'] = getWeight(str[i], j);
// (char) - 'a', gives an integer value for the small case alphabets (a->1, b->2, c->3 ...)
}
}
}
getWeight()
int getWeight(char s[], int j) {
// returns the integer on left of '.' from the string
int w = 0,i = 0;
int m = 1;
for (i = j-1; s[i] >= '0' && s[i] <= '9'; --i) {
w += (s[i] - '0')*m;
m *= 10;
}
return w;
}
如果您真的需要使用该结构,那么您可以通过使每个商店的 weights
数量等于 connectingPoints
数量来简化它。即,如果您要添加 store[0].connectingPoints[0] = 'a';
,则权重为
store[0].weights[0] = 0; // weight of point a to point a
store[0].weights[1] = 2; // weight of point a to point b
store[0].weights[2] = 1; // weight of point a to point d
另一个例如:"c = 2.b, 1.f",
(不确定代码中 connectingPoints
的顺序是什么,但请注意基于索引的点和权重的一对一映射)
store[2].connectingPoints[0] = 'b';
store[2].connectingPoints[1] = 'c';
store[2].connectingPoints[2] = 'f';
store[2].weights[0] = 2;
store[2].weights[1] = 0;
store[2].weights[2] = 1;
如果你知道没有自循环,你可以避免将它们存储在 connectedPoints
中并进一步添加相应的条目到 weights
.
在这种情况下,您可以使用这样的循环构建 adjmatrix
struct stopPoints store[26];
for (i = 0; i < n; ++i) {
int l = strlen(store[i].connectingPoints);
for (j = 0; j < l; ++j) {
adjmatrix[str[i][0] - 'a'][store[i].connectingPoints[j] - 'a'] = store[i].weights[j];
}
}
字符到整数的转换
您可以找到 ASCII table here 的副本。您应该将此页面添加为书签,因为如果您花很多时间编程,您会经常参考它(每年两次,比如说,持续 30 多年)。
了解 ASCII 码(Latin1、Unicode 等的子集)的重要一点是数字、大写字母和小写字母位于三个连续的组中,按升序排列。
即'0'的代码比'1'的代码少1,以此类推,直到'9'。 'A'..'Z' 和 'a'..'z'.
也是如此因此您可以通过简单的减法将字符值转换为索引值:
int ch0 = 'a' - 'a'; // == 0
int ch1 = 'b' - 'a'; // == 1
int ch4 = 'e' - 'a'; // == 4
如果您有一个(小写,ASCII)字符值,并从中减去 'a',您将得到一个 0..25.
范围内的整数值这意味着您可以使用该公式计算邻接矩阵的两个索引值:
#define MAX_CONN 10
#define NUM_STORES 12
#define STORE_INDEX(ch) ((ch) - 'a')
#define FIRST_STORE 'a'
#define END_STORES (FIRST_STORE + NUM_STORES)
#define MAX_WEIGHT 100
// NOTE: I'm ignoring return type, and adjmatrix's
// lifetime, in favor of just putting this code all
// in one place. You'll have to figure out the rest.
void build_adj() {
struct stopPoints store[NUM_STORES]; // Values?
int adjmatrix[NUM_STORES][NUM_STORES] = {0};
for (st = FIRST_STORE; st < END_STORES; ++st) {
int row = STORE_INDEX(st);
// Set default weights: MAX_WEIGHT or 0 (for self)
for (i = 0; i < NUM_STORES; ++i) {
adjmatrix[row][i] = MAX_WEIGHT;
}
adjmatrix[row][row] = 0;
// Install parsed weights for this row
for (iconn = 0; iconn < MAX_CONN; ++iconn) {
// NB: setting connectingPoints[x] to '[=11=]' invalidates connection.
char st2 = store[row].connectingPoints[iconn];
if (st2 != '[=11=]') {
adjmatrix[row][STORE_INDEX(st2)] = store[row].weights[iconn];
// FIXME: Maybe set reflexive weight? a->b, b->a?
}
}
}
}
Struct/Array反转
现在你有一个包含一对数组的结构数组。我建议您将其反转,并构建一个结构数组,其中包含一个包含具有两个数据元素的结构的数组。
像这样:
typedef struct Connection {
char conn_target;
int conn_weight;
} Connection;
typedef struct StopPoints {
Connection sp_connections[MAX_CONN];
} StopPoints;
然后你有:
StopPoints store[MAX_STORES];
// most code stays the same
st2 = store[row].sp_connections[iconn].conn_target;
// ...
adjmatrix[row][STORE_INDEX(st2)] = store[row].sp_connections[iconn].conn_weight;
这样做的好处是概念上的:连接目标和权重捆绑在同一个结构中。它使这更容易思考,也更容易转换为使用指针 ;-)。
另一方面,由于结构填充,它会占用更多内存。但我认为你现在不关心这个。