我认为这一定很简单,但我做不到......
我有一个MxM三角矩阵,其系数逐行存储在矢量中。 例如:
M = [ m00 m01 m02 m03 ]
[ m11 m12 m13 ]
[ m22 m23 ]
[ m33 ]
存储为
coef[ m00 m01 m02 m03 m11 m12 m13 m22 m23 m33 ]
现在我正在寻找一种非递归算法,它可以提供矩阵大小M
和系数数组索引i
unsigned int row_index(i,M)
和
unsigned int column_index(i,M)
它引用的矩阵元素的。所以,
如果索引计数从零开始,则为row_index(9,4) == 3
,column_index(7,4) == 2
等。
编辑:已经给出了几个使用迭代的回复。有没有人知道代数表达式?
答案 0 :(得分:20)
本回复最后的单行,解释如下: - )
系数数组具有:第一行的M个元素(索引中的第0行),第二行(第1行)的(M-1),依此类推,总共为M +(M-1) + ... + 1 = M(M + 1)/ 2个元素。
从最后开始工作会稍微容易一些,因为系数数组总是最后一行(行M-1)有1个元素,第二行有2个元素(行M- 2),行M-3的3个元素,依此类推。最后K行占用系数数组的最后K(K + 1)/ 2个位置。
现在假设你在系数数组中得到一个索引i。在大于i的位置处存在M(M + 1)/ 2-1-i个元素。拨打这个号码我'; 你想要找到最大的k,使得k(k + 1)/2≤i'。这个问题的形式是你苦难的根源 - 据我所见,你无法避免占据平方根: - )
无论如何,让我们这样做:k(k + 1)≤2i'表示(k + 1/2) 2 - 1 /4≤2i',或等效k≤(sqrt(8i) “+ 1)-1)/ 2。让我将最大的k称为K,然后有K行(稍后是总共M行),因此row_index(i,M)是M-1-K。对于列索引,i'中的K(K + 1)/ 2个元素在后面的行中,因此该行中有j'= i'-K(K + 1)/ 2个后面的元素(具有总共K + 1个元素),因此列索引为K-j'。 [或等效地,此行从结尾开始于(K + 1)(K + 2)/ 2,因此我们只需要从i中减去该行的起始位置:i- [M(M + 1)/ 2 - (K + 1)(K + 2)/ 2]。令人鼓舞的是,两个表达都给出了相同的答案!]
(伪)代码[使用ii代替i',因为某些语言不允许使用名称为i'的变量; - )]:
row_index(i, M):
ii = M(M+1)/2-1-i
K = floor((sqrt(8ii+1)-1)/2)
return M-1-K
column_index(i, M):
ii = M(M+1)/2-1-i
K = floor((sqrt(8ii+1)-1)/2)
return i - M(M+1)/2 + (K+1)(K+2)/2
当然,您可以通过将表达式替换为ii和K来将它们转换为单行。您可能必须注意精度误差,但是有一些方法可以找到不需要浮点计算的整数平方根。另外,引用Knuth:“注意上面代码中的错误;我只是证明它是正确的,没有尝试过。”
如果我冒昧地进一步评论:简单地将所有值保持在M×M阵列中将最多占用两倍的内存,并且根据您的问题,与算法改进相比,因子2可能无关紧要,并且可能值得交换平方根的可能昂贵的计算,以获得更简单的表达式。
[编辑:BTW,你可以证明楼层((sqrt(8ii + 1)-1)/ 2)=(isqrt(8ii + 1)-1)/ 2其中isqrt(x)= floor(sqrt( x))是整数平方根,除法是整数除法(截断; C / C ++ / Java等中的默认值) - 所以如果你担心精度问题,你只需要担心实现一个正确的整数平方根。]
答案 1 :(得分:7)
这是一个代数(主要)解决方案:
unsigned int row_index( unsigned int i, unsigned int M ){
double m = M;
double row = (-2*m - 1 + sqrt( (4*m*(m+1) - 8*(double)i - 7) )) / -2;
if( row == (double)(int) row ) row -= 1;
return (unsigned int) row;
}
unsigned int column_index( unsigned int i, unsigned int M ){
unsigned int row = row_index( i, M);
return i - M * row + row*(row+1) / 2;
}
编辑:修复了row_index()
答案 2 :(得分:2)
必须是那个
i == col + row*(M-1)-row*(row-1)/2
因此,找到col和row的一种方法是迭代row的可能值:
for(row = 0; row < M; row++){
col = i - row*(M-1)-row*(row-1)/2
if (row <= col < M) return (row,column);
}
这至少是非递归的,我不知道你是否可以在没有迭代的情况下做到这一点。
从这个和其他答案中可以看出,你几乎必须计算行才能计算列,所以在一个函数中同时执行这两个操作可能是明智的。
答案 3 :(得分:2)
这些可能有一个聪明的衬垫,但(减去任何错误检查):
unsigned int row_index( unsigned int i, unsigned int M ){
unsigned int row = 0;
unsigned int delta = M - 1;
for( unsigned int x = delta; x < i; x += delta-- ){
row++;
}
return row;
}
unsigned int column_index( unsigned int i, unsigned int M ){
unsigned int row = 0;
unsigned int delta = M - 1;
unsigned int x;
for( x = delta; x < i; x += delta-- ){
row++;
}
return M + i - x - 1;
}
答案 4 :(得分:2)
ShreevatsaR的解释非常好,帮助我解决了我的问题。但是,为列索引提供的解释和代码给出的答案与问题要求的答案略有不同。
重申一下,i之后的行中有j'= i' - K(K + 1)/ 2个元素。但是,就像所有其他行一样,该行具有M个元素。因此,(从零开始)列索引是y = M-1-j'。
相应的伪代码是:
column_index(i, M):
ii = M(M+1)/2-1-i
K = floor((sqrt(8ii+1)-1)/2)
jj = ii - K(K+1)/2
return M-1-jj
ShreevatsaR给出的答案,K - j',是从矩阵的对角线开始计数(零)时的列索引。因此,他的计算给出column_index(7,4)= 0,而不是如问题中所指定的,column_index(7,4)= 2.
答案 5 :(得分:1)
我想了一下,我得到了以下结果。请注意,您只需一次获得行和列。
假设:行开始为0.列从0开始。索引从0开始
符号
N =矩阵大小(原问题中为M)
m =元素的索引
伪代码是
function ind2subTriu(m,N)
{
d = 0;
i = -1;
while d < m
{
i = i + 1
d = i*(N-1) - i*(i-1)/2
}
i0 = i-1;
j0 = m - i0*(N-1) + i0*(i0-1)/2 + i0 + 1;
return i0,j0
}
一些八度/ matlab代码
function [i0 j0]= ind2subTriu(m,N)
I = 0:N-2;
d = I*(N-1)-I.*(I-1)/2;
i0 = I(find (d < m,1,'last'));
j0 = m - d(i0+1) + i0 + 1;
您怎么看?
截至2011年12月,在GNU / Octave中添加了非常好的代码。他们可能会扩展sub2ind和ind2sub。目前,代码可以作为私有函数ind2sub_tril和sub2ind_tril
找到答案 6 :(得分:0)
花了一些时间来了解你的需求! :)
unsigned int row_index(int i, int m)
{
int iCurrentRow = 0;
int iTotalItems = 0;
for(int j = m; j > 0; j--)
{
iTotalItems += j;
if( (i+1) <= iTotalItems)
return iCurrentRow;
iCurrentRow ++;
}
return -1; // Not checking if "i" can be in a MxM matrix.
}
抱歉忘记了其他功能.....
unsigned int column_index(int i, int m)
{
int iTotalItems = 0;
for(int j = m; j > 0; j--)
{
iTotalItems += j;
if( (i+1) <= iTotalItems)
return m - (iTotalItems - i);
}
return -1; // Not checking if "i" can be in a MxM matrix.
}