有没有人知道对矩阵进行右循环移位的有效方法?顺便说一下,矩阵是二进制的,但解决非二元矩阵的方法也很好。
现在,我正在考虑为矩阵的行实现一个圆形数组,并在需要移位操作时更新每一行。
我正在考虑的另一种方法是实现一个指向矢量的指针向量(矩阵的),这些指针由向量表示,并在发生移位操作时将它们交换。
E.g。
1 2 3
4 5 6
7 8 9
右移
3 1 2
6 4 5
9 7 8
如果我还需要将矩阵向下移动,所有这些解决方案都会出现另一个问题。要有效地实施这两项行动,完全超出我的范围。
降档
9 7 8
3 1 2
6 4 5
答案 0 :(得分:2)
或许这样的事情,
class matrix {
std::vector<bool> elements;
int rows, cols, row_ofs, col_ofs;
std::size_t index(int r, int c) {
r = (r + row_ofs) % rows;
c = (c + col_ofs) % cols;
return std::size_t(r)*cols + c; // row major layout
}
public:
matrix() : rows(0), cols(0) {}
matrix(int r, int c)
: elements(std::size_t(r)*c), rows(r), cols(c) {}
int num_rows() const { return rows; }
int num_cols() const { return cols; }
std::vector<bool>::reference operator()(int r, int c) {
return elements.at(index(r,c));
}
bool operator()(int r, int c) const {
return elements.at(index(r,c));
}
void rotate_left() { col_ofs = (col_ofs+1 ) % cols; }
void rotate_right() { col_ofs = (col_ofs+cols-1) % cols; }
void rotate_up() { row_ofs = (row_ofs+1 ) % rows; }
void rotate_down() { row_ofs = (row_ofs+rows-1) % rows; }
};
(未测试的)
编辑:这是另一种选择:使用std :: deque&lt; std :: deque&lt; T&gt; &GT;内部。 ;-) 是的,它 支持随机访问。双端队列不是列表。另外,您不需要再使用模运算。
答案 1 :(得分:1)
不确定你的意思。通常将右移应用于缓冲器或行向量。答案取决于矩阵的存储方式。
如果内存布局允许,旋转数组的有效方法是将第一个值复制到数组的末尾,然后将指针移到一个元素的数组中。这仅适用于为阵列分配足够空间且不要旋转太多次的情况。
或者,您可以将阵列保持在原位并有一个指向“左端”的额外指针,注意在其他操作中正确处理所有环绕。
否则,您可能需要执行大量的memcopying。
编辑:我看到你刚刚更新了问题以包含这个答案。
其他编辑:从示例中,您似乎不需要单独移动行和列。如果是这种情况,那么您只需要存储“左上角”索引的坐标并修改所有矩阵运算以适当地查找数据结构中的值。
然后问题就变成了你想要效率的问题。你打算做很多班次操作吗?如果没有,那么通过额外的查找可能不值得减慢所有乘法运算。
如果你确实使用查找的想法,绝对不要使用mod运算符。这是非常低效的。相反,对于移位,只需测试大于行或列的长度,并在需要时减去长度。
答案 2 :(得分:1)
我正在考虑的另一种方法是实现一个指向矢量的指针向量(矩阵的),这些指针由向量表示,并在发生移位操作时将它们交换。
我会为列(水平移位)和行的另一个向量(垂直移位)执行此操作。
我还会创建一个Matrix对象来封装你的“真实”矩阵和这两个向量。对象的getter / setter会引用这两个向量来访问“real”矩阵中的数据,你会有像“horizontalShift(...)”和“verticalShift(...)”这样的方法只交换你的值两个向量,就像你建议的那样。
这是最快的实施吗?还有一个间接访问数据(尽管仍为O(1)),交换对于水平移位为O(m),对于垂直移位为O(n)(对于n×m矩阵)使用向量。
答案 3 :(得分:0)
有些方法可以非常快速地进行移位,但在尝试“使用”矩阵时会导致效率低下,例如:打印,点\交叉产品。
例如,如果我的矩阵定义为“int m [3] [2];”我可能只是使用索引来定义第一列索引。因此,移位只是该索引的加法\减法(不修改数据)。
另一个例子;如果要将矩阵限制为二进制,可以将矩阵打包成单个变量并使用位移(向左/向右旋转)。
然而,这两种方法都会使其他操作变得更加复杂。
我想这一切都取决于矩阵的使用范围以及你想要它的通用程度。
答案 4 :(得分:0)
使用Eigen library非常简单:
Eigen::Matrix<int, 3, 3> A;
A << 1, 2, 3,
4, 5, 6,
7, 8, 9;
std::cout << A << std::endl << std::endl;
// Right-shift:
A.col(0).swap(A.col(1));
A.col(0).swap(A.col(2));
std::cout << A << std::endl << std::endl;
// Down-shift:
A.row(0).swap(A.row(1));
A.row(0).swap(A.row(2));
std::cout << A << std::endl << std::endl;
对于Eigen-MATLAB对应,有一个非常有用的reference guide。
答案 5 :(得分:0)
我通过反时钟移位实现了递归C ++版本:
// rotateMatrix.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
using namespace std;
void rotatematrix(int M[][3], int row, int col, int rowLen, int colLen)
{
//rowLen & colLen are always the orginal matrix total length
// playRows & playCols are the size for the current recuision
// row & col are the starting position related to the original matrix(0,0)
int playRows = rowLen - 2*row ;
int playCols = colLen - 2*col;
if (playCols <= 1 || playRows <= 1)
return;
//row,col is the starting point pointing to the top left corner element
if (rowLen <= 1 || colLen <= 1) return;
int tmp = M[row][col];
//left shift the top row by one element
for (int j = col; j <= playCols + col - 2; ++j)
M[row][j] = M[row][j + 1];
// up shift the right colunm by one position
for (int i = row; i <= playRows + row - 2; ++i)
M[i][col + playCols - 1] = M[i + 1][col + playCols - 1];
//right shift the bottom row by one
for (int j = col + playCols - 2; j >= col; --j)
M[row+playRows-1][j+1] = M[row+playRows-1][j];
// down shift the left col by one
for (int i = row + playRows - 2; i >= row; --i)
M[i+1][col] = M[i][col];
M[row + 1][col] = tmp;
rotatematrix(M, ++row, ++col, rowLen, colLen);
}
int _tmain(int argc, _TCHAR* argv[])
{
// Test Case 1
/*
int a[4][4] = { { 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 },
{ 13, 14, 15, 16 } };
int R = 4, C = 4;*/
// Tese Case 2
int R = 3, C = 3;
int a[3][3] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int i = 0; i<R; i++)
{
for (int j = 0; j<C; j++)
cout << a[i][j] << " ";
cout << endl;
}
rotatematrix(a, 0, 0, 3, 3);
// Print rotated matrix
for (int i = 0; i<R; i++)
{
for (int j = 0; j<C; j++)
cout << a[i][j] << " ";
cout << endl;
}
return 0;
}
答案 6 :(得分:0)
我已经编写了用于以圆形方式逐层旋转数组的代码。
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n;
int value=1;
scanf("%d",&n);
int arr[n][n];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
arr[i][j]=value++;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
printf("%d\t",arr[i][j]);
printf("\n");
}
for(int r1=0,r2=n-1,c1=0,c2=n-1;r1<=r2;r1++,r2--,c1++,c2--)
{
int temp=arr[c1][r2];
for(int i=r2;i>r1;i--)
arr[c1][i]=arr[c1][i-1];
int temp2=arr[c2][r2];
for(int i=c2;i>c1;i--)
if(i!=c1+1)
arr[i][r2]=arr[i-1][r2];
else
arr[i][r2]=temp;
temp=arr[c2][r1];
for(int i=r1;i<r2;i++)
if(i!=r2-1)
arr[c2][i]=arr[c2][i+1];
else
arr[c2][i]=temp2;
for(int i=c1;i<c2;i++)
if(i!=c2-1)
arr[i][r1]=arr[i+1][r1];
else
arr[i][r1]=temp;
}
printf("\n\n");
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
printf("%d\t",arr[i][j]);
printf("\n");
}
return 0;
}
示例代码正常工作