矩阵循环移位

发布于 2024-08-05 18:46:37 字数 391 浏览 2 评论 0 原文

有谁知道对矩阵进行右循环移位的有效方法?顺便说一句,矩阵是二元矩阵,但求解非二元矩阵的方法也很好。

现在,我正在考虑为矩阵的行实现一个圆形数组,并在需要移位操作时更新每一行。

我正在考虑的另一种方法是实现一个指向由向量表示的列(矩阵)的指针向量,并在发生移位操作时交换它们。

例如,

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

Does anyone know an efficient way to right circular-shift a matrix? Btw, the matrix is binary but a method to solve a non-binary matrix is also fine.

Right now, I'm thinking of implementing a circular array for the rows of my matrix and updating each row whenever a shift operation is required.

Another method, I was considering was implementing a vector of pointers to columns (of the matrix) represented by vectors and swapping them around when a shift operation occurs.

E.g.

1 2 3
4 5 6
7 8 9

Right-shift

3 1 2
6 4 5
9 7 8

Another problem arises with all these solutions if I need to shift the matrix down as well. To implement both operations efficiently, is completely beyond me.

Down-shift

9 7 8
3 1 2
6 4 5

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

迷离° 2024-08-12 18:46:38

使用 Eigen 库非常简单:

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 对应参考指南

Using Eigen library it is very simple:

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;

There is a very useful reference guide for Eigen-MATLAB correspondence.

开始看清了 2024-08-12 18:46:38

我通过逆时针移位实现了递归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;
}

I implemented a recursion C++ version by anti clock wise shift:

// 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;
}
橘味果▽酱 2024-08-12 18:46:38

我编写了用于以圆形方式逐层旋转数组的代码。

#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;
}

示例代码工作:

在此处输入图像描述

I have made code for rotating an array in circular fashion layer by layer.

#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;
}

Sample code working:

enter image description here

初见终念 2024-08-12 18:46:37

也许是这样的,

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 >内部。 ;-)
是的,它确实支持随机访问。双端队列不是列表。另外,您不再需要为模运算而烦恼。

Something like this perhaps,

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; }
};

(untested)

Edit: Here's an alternative: Use std::deque<std::deque<T> > internally. ;-)
Yes, it does support random access. A deque is not a list. Plus, you don't need to bother anymore with the modulo arithmetic.

酒解孤独 2024-08-12 18:46:37

不确定你的意思到底是什么。通常右移应用于缓冲区或行向量。答案取决于矩阵的存储方式。

如果内存布局允许,旋转数组的一种有效方法是将第一个值复制到数组的末尾,然后将指向数组的指针向上移动一个元素。仅当您为阵列分配足够的空间并且不旋转太多次时,这才有效。

或者,您可以将数组保留在适当的位置,并有一个指向“左端”的额外指针,并注意在其他操作中正确处理所有环绕。

否则,您可能需要执行大量内存复制。

编辑:我看到您刚刚更新了问题以包含此答案。

其他编辑:从示例中,您似乎不需要独立移动行和列。如果是这种情况,那么您只需要存储“左上角”索引的坐标并修改所有矩阵运算以适当地查找数据结构中的值。

那么您面临的问题就变成了您想要的效率问题。您要进行多次轮班操作吗?如果不是,那么可能不值得通过额外的查找来减慢所有乘法运算的速度。

如果你确实使用查找的想法,绝对不要使用 mod 运算符。这是极其低效的。相反,对于移位,只需测试是否大于行或列长度,并在需要时减去长度。

Not sure what you mean exactly. Usually right-shift is applied to a buffer or row vector. The answer will depend on how your matrix is stored.

An efficient way to rotate an array, if the memory layout allows it, is to copy the first value to the end of the array and then move the pointer to the array up one element. This will only work if you allocate enough room for the array and don't rotate too many times.

Or, you can just keep the array in place and have an extra pointer to the "left end", taking care to handle all the wrapping around correctly in your other operations.

Otherwise, you will probably have to perform a lot of memcopying.

Edit: I see you just updated the question to include this answer.

Other edit: From the examples, you don't seem to need to shift the rows and columns independently. If that is the case, then you just need to store the coordinates of the "top left" index and modify all the matrix operations to lookup values in the data structure appropriately.

The issue for you then becomes a question of where you want the efficiency. Are you going to be performing many shift operations? If not, then it might not be worth slowing down all the multiplication operations with an extra lookup.

And if you do use the lookup idea, definitely DO NOT use a mod operator. It is incredibly inefficient. Instead, for a shift, just test for greater than row or column length and subtract the length when needed.

不爱素颜 2024-08-12 18:46:37

我正在考虑的另一种方法是实现一个指向由向量表示的列(矩阵)的指针向量,并在发生移位操作时交换它们。

我会对列(水平移位)执行此操作,对行执行另一个向量(垂直移位)。

我还将创建一个 Matrix 对象来封装您的“真实”矩阵和这两个向量。对象的 getter/setter 将引用这两个向量来访问“真实”矩阵中的数据,并且您将拥有诸如“horizo​​ntalShift(...)”和“verticalShift(...)”之类的方法,这些方法仅交换您的“真实”矩阵中的值。两个向量,就像你建议的那样。

这会是最快的实施吗?还有一种间接访问数据的方式(尽管仍然是 O(1)),并且使用向量进行水平移位的交换为 O(m),垂直移位的交换为 O(n)(对于 m 矩阵)。

Another method, I was considering was implementing a vector of pointers to columns (of the matrix) represented by vectors and swapping them around when a shift operation occurs.

I would do this for the columns (horizontal shift) and another vector for the rows (vertical shift).

I would also create a Matrix object to encapsulate your "real" matrix and these two vectors. The getters/setters of your object would reference those two vectors to access data in your "real" matrix and you would have methods like "horizontalShift(...)" and "verticalShift(...)" that only swap values in your two vectors, like you suggested.

Would it be the fastest implementation ? There one more indirection to access the data (still O(1) though) and the swapping would be O(m) for horizontal shift and O(n) for vertical shift (for a n by m matrix) using vectors.

御弟哥哥 2024-08-12 18:46:37

有些方法可以使移位本身非常快,但在尝试“使用”矩阵时会导致效率低下,例如打印、点\叉积。

例如,如果我有一个定义为“int m[3][2];”的矩阵我可能只使用索引来定义第一列索引。因此,移位只是该一个索引的加减(不修改数据)。

另一个例子;如果您想将矩阵限制为二进制,您可以将矩阵打包到单个变量中并使用位移位(左\右旋转)。

然而,这两种方法都会使其他操作变得更加复杂。

我想这完全取决于矩阵的使用范围以及您希望它的通用性。

There are methods that make doing the shift itself very fast, but result in inefficiencies when trying to 'use' the matrix, e.g. print, dot\cross products.

For example, if I had a matrix defined like "int m[3][2];" I might just use an index to define the first column index. Thus a shift is just an add\subtract of that one index (no modification of the data).

Another example; if you want to restrict the matrix to being binary, you could pack the matrix into a single variable and use bit shifts (rotate left\right).

Both of these methods would make other operations more complex however.

I guess it all depends on the scope of how the matrix is going to be used and how generic you want it to be.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文