行和列交换是否有高效的数据结构?

时间:2011-08-15 07:19:25

标签: data-structures computer-science

我有一个数字矩阵,我希望能够:

  1. 交换行
  2. 交换列
  3. 如果我要使用指向行的指针数组,那么我可以轻松地在O(1)中的行之间切换,但是交换列是O(N),其中N是行数。

    我有一种明显的感觉,没有双赢的数据结构为这两种操作提供O(1),但我不确定如何证明它。或者我错了吗?

2 个答案:

答案 0 :(得分:3)

没有完全考虑到这一点:

我认为你对行指针的想法是正确的开始。然后,为了能够“交换”列,我只有另一个具有列数大小的数组,并在每个字段中存储列的当前物理位置的索引。

m = 
[0] -> 1 2 3
[1] -> 4 5 6
[2] -> 7 8 9 

c[] {0,1,2}

现在要交换第1列和第2列,您只需将c更改为{0,2,1}

即可

当你想阅读第1行时,你会做

for (i=0; i < colcount; i++) {
   print m[1][c[i]];
}

答案 1 :(得分:0)

这里只是一个随机的(没有经验,这真的有效,而且是一个没有咖啡的深夜):

我在想的是矩阵的内部是哈希表而不是数组。

数组中的每个单元格都有三条信息:

  1. 单元格所在的行
  2. 单元格所在的列
  3. 单元格的值
  4. 在我看来,这很容易用元组((i, j), v)表示,其中(i, j)表示单元格的位置(第i行,第j列),v

    这将是矩阵的某种正常表示。但是让我们来看看这里的想法。而不是i将行表示为一个位置(即在3之前的1之前的0等等),我们只考虑i作为其对应行的某种规范标识符。让我们对j做同样的事情。 (虽然在最一般的情况下,ij可以不受限制,让我们假设一个简单的情况,它们将保持在[0..M]和[0..N]的范围内M x N矩阵,但不表示单元格的实际坐标。)

    现在,我们需要一种方法来跟踪行的标识符以及与该行关联的当前索引。这显然需要键/值数据结构,但由于索引的数量是固定的(矩阵通常不会增长/缩小),并且只处理积分索引,我们可以将其实现为固定的一维数组。对于M行的矩阵,我们可以(在C中):

    int RowMap[M];
    

    对于第m行,RowMap[m]给出当前矩阵中行的标识符。

    我们将对列使用相同的东西:

    int ColumnMap[N];
    

    其中ColumnMap[n]是第n列的标识符。

    现在回到我在开头提到的哈希表:

    由于我们有完整的信息(矩阵的大小),我们应该能够生成一个完美的散列函数(没有碰撞)。这是一种可能性(对于适度大小的数组):

    int Hash(int row, int column)
    {
        return row * N + column;
    }
    

    如果这是哈希表的哈希函数,对于大多数大小的数组,我们应该得到零冲突。这允许我们在O(1)时间内从散列表读取/写入数据。

    很酷的部分是将每个行/列的索引与哈希表中的标识符连接起来:

    // row and column are given in the usual way, in the range [0..M] and [0..N]
    // These parameters are really just used as handles to the internal row and
    // column indices
    int MatrixLookup(int row, int column)
    {
        // Get the canonical identifiers of the row and column, and hash them.
        int canonicalRow = RowMap[row];
        int canonicalColumn = ColumnMap[column];
        int hashCode = Hash(canonicalRow, canonicalColumn);
    
        return HashTableLookup(hashCode);
    }
    

    现在,由于矩阵的接口仅使用这些句柄而不是内部标识符,因此行或列的swap操作对应于RowMap或{{1}中的简单更改数组:

    ColumnMap

    那应该是它 - 具有O(1)访问和变异的矩阵,以及O(1)行交换和O(1)列交换。当然,即使O(1)散列访问也比基于数组的访问的O(1)慢,并且将使用更多内存,但至少在行/列之间存在相等。

    当涉及到你如何实现你的矩阵时,我试图尽可能不可知。所以我写了一些C.如果你更喜欢另一种语言,我可以改变它(如果你理解的话,那将是最好的),但是我认为这是非常自我描述的,虽然我不能确保它的纠正性,就C来说,因为我实际上是一个C ++家伙,现在正试图扮演一个C家伙(我提到我没有喝咖啡) ?)。就个人而言,用完整的OO语言写作会使得设计更加公正,并且还会给代码带来一些美感,但就像我说的那样,这是一个快速的实施。