我正在尝试用C语言编写一个函数,该函数将NxM矩阵作为输入,如果发现空列,则根据用户的选择将非空列移至矩阵的左侧或右侧空列可以是1,2或更多。
作为一个例子。假设下面的矩阵:
矩阵元素是:
1 2 3 4 5 6 7 8
------------------
1| 1 6 0 0 0 1 0 8
2| 1 3 0 3 0 1 0 0
3| 3 0 0 0 0 8 0 0
4| 0 0 0 2 6 0 0 4
如您所见,只有第3列和第7列完全为空(全为0)。我想要一个函数,如果用户选择l(左),它将把不为空的列向左移动。因此它将返回:
矩阵元素是:
1 2 3 4 5 6 7 8
------------------
1| 1 6 0 0 1 8 0 0
2| 1 3 3 0 1 0 0 0
3| 3 0 0 0 8 0 0 0
4| 0 0 2 6 0 4 0 0
如果用户选择r(代表右),它将把非空列移到右边,因此函数将返回:
矩阵元素是:
1 2 3 4 5 6 7 8
------------------
1| 0 0 1 6 0 0 1 8
2| 0 0 1 3 3 0 1 0
3| 0 0 3 0 0 0 8 0
4| 0 0 0 0 2 6 0 4
这是我的第一个方法:
void PushL(int (*arr), int rows, int cols){ //function to move columns to left
for(int i = 0; i < rows; i++)
for(int j = 0;j < cols; j++){
if(arr[i*cols+j] == 0)
for(int k = j + 1; k < cols; k++){
if(arr[i*cols+k] != 0){
arr[i*cols+j] = arr[i*cols+k];
arr[i*cols+k] = 0;
break;
}
}
}
}
答案 0 :(得分:1)
这可能不是唯一的问题,但是原始帖子中显示的两个代码段都缺少{}
符号,这对于假定的意图至关重要。 (请参见/// here
)
void PushR(int (*arr), int rows, int cols){
for(int i = rows; i > 0; i--)
for(int j = cols;j > 0; j--){
if(arr[i*cols+j] == 0)
for(int k = j + 1; k < cols; k++){
if(arr[i*cols+k] != 0)
{ /// here
arr[i*cols+j] = arr[i*cols+k];
arr[i*cols+k] = 0;/// without {} these lines will be executed
break; /// regardless of if evaluation
} /// and here
}
}
}
(C中的缩进仅出于可读性,并不控制执行流程。)
要使代码对以后将要维护的代码更具可读性,最好消除所有关于意图的歧义:(包括在括号中未明确知道意图的花括号。)
void PushR(int (*arr), int rows, int cols){
for(int i = rows; i > 0; i--) {/// added here
for(int j = cols;j > 0; j--){
if(arr[i*cols+j] == 0) { /// added here
for(int k = j + 1; k < cols; k++){
if(arr[i*cols+k] != 0) { /// here
arr[i*cols+j] = arr[i*cols+k];
arr[i*cols+k] = 0;
break;
} /// and here
}
}
}
}
}
答案 1 :(得分:1)
出于有关{}丢失的问题,您的程序无法正常工作,因为您只考虑值等于0的单元格,还是不考虑同一列中的其他单元格。
您需要先确定该列是否全部包含 ,然后才能决定是否将其移动
为此:
int onlyZero(int (*arr), int col, int rows, int cols)
{
const int sup = cols*rows;
for (int i = 0; i != sup; i += cols) {
if (arr[i + col] != 0)
return 0;
}
return 1;
}
如果列 col 仅包含0,则返回1,否则返回0
要复制另一列:
void copyColumn(int (*arr), int fromCol, int toCol, int rows, int cols)
{
int sup = cols*rows;
for (int i = 0; i != sup; i += cols)
arr[i + toCol] = arr[i + fromCol];
}
并重置列:
void resetColumn(int (*arr), int col, int rows, int cols)
{
int sup = cols*rows;
for (int i = 0; i != sup; i += cols)
arr[i + col] = 0;
}
使用这些功能,即使这样也不是更快的方法:
void PushL(int (*arr), int rows, int cols)
{
int receiver = 0;
for (int col = 0; col != cols; ++col) {
if (!onlyZero(arr, col, rows, cols)) {
if (receiver != col)
copyColumn(arr, col, receiver, rows, cols);
receiver += 1;
}
}
while (receiver != cols)
resetColumn(arr, receiver++, rows, cols);
}
添加
void pr(int (*arr), int rows, int cols)
{
for (int row = 0; row != rows; ++row) {
for (int col = 0; col != cols; ++col) {
printf("%d ", arr[row*cols + col]);
}
putchar('\n');
}
putchar('\n');
}
int main()
{
int a[] = {
1, 6, 0, 0, 0, 1, 0, 8,
1, 3, 0, 3, 0, 1, 0, 0,
3, 0, 0, 0, 0, 8, 0, 0,
0, 0, 0, 2, 6, 0, 0, 4
};
pr(a, 4, 8);
PushL(a, 4, 8);
pr(a, 4, 8);
}
编译和执行:
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall m.c
pi@raspberrypi:/tmp $ ./a.out
1 6 0 0 0 1 0 8
1 3 0 3 0 1 0 0
3 0 0 0 0 8 0 0
0 0 0 2 6 0 0 4
1 6 0 0 1 8 0 0
1 3 3 0 1 0 0 0
3 0 0 0 8 0 0 0
0 0 2 6 0 4 0 0
我让您执行与PushL非常接近的PushR
PushR 是 PushL 的对称符号:
void PushR(int (*arr), int rows, int cols)
{
int receiver = cols - 1;
for (int col = cols-1; col != -1; --col) {
if (!onlyZero(arr, col, rows, cols)) {
if (receiver != col)
copyColumn(arr, col, receiver, rows, cols);
receiver -= 1;
}
}
while (receiver != -1)
resetColumn(arr, receiver--, rows, cols);
}
答案 2 :(得分:0)
void test()
{
int p[4][9] = {
1 , 1, 6, 0, 0, 0, 1, 0, 8,
2 , 1, 3, 0, 3, 0, 1, 0, 0,
3 , 3, 0, 0, 0, 0, 8, 0, 0,
4 , 0, 0, 0, 2, 6, 0, 0, 4 };
int pp[4][9] = {};
int say = 0;
for (int i = 0; i < 9; i++)
{
bool ok = false;
for (int j = 0; j < 4; j++)
{
if (p[j][i] != 0)
ok = true;
}
if (ok)
{
for (int j = 0; j < 4; j++)
pp[j][say] = p[j][i];
say++;
}
}
for (int j = 0; j < 4; j++)
for (int i = 0; i < 9; i++)
{
printf("%d ", pp[j][i]);
if (i == 8) printf("\n");
}
}