索引集合的(无序)对

时间:2014-01-24 11:21:54

标签: algorithm sorting

这是一个自动回答的问题,源自this more specific question,在选择错误的(恕我直言)答案后,OP似乎已失去兴趣。

我确实检查了之前关于这个问题的问题,但似乎都没有解决这个问题。

有什么用?

想象一下,你有4个人:Abdul,Beatrix,Charlie和Daria 你想存储关于这些人对彼此的感受的信息

Abdul and Beatrix are in love
Beatrix and Charlie hate each other
Abdul and Charlie are good friends
Daria and Beatrix don't know each other
etc.

在简洁而没有诗歌的计算机世界中,这可以转化为:

relation (Abdul  , Beatrix) = love;
relation (Beatrix, Charlie) = hate;
relation (Abdul  , Charlie) = friendship;
etc.

换句话说,如果您想映射每对人之间的关系,您将需要一个数据结构,允许您为每对人保持唯一值。

尽管有许多方法可以实现合适的数据结构,但在某些情况下,您可能希望此表是一个固定大小的数组,直接由表示给定关系的对索引。

一些定义:

给定I N 前N个自然整数的集合,让我们称之为P N I N的所有无序对(a,b)的序列使得<> b,按字典顺序排序。

在(希望)不那么神秘的英语中, P列举了我 的两个元素之间的所有可能关系。

示例(对于N = 4):

4 =(0,1,2,3)
P 4 =((0,1),(0,2),(0,3),(1,2),(1,3),(2,3))

请注意,P N 的基数为N(N-1)/ 2,因此
P N 中最紧凑的零基指数将在[0..N(N-1)/ 2-1]范围内

问题:

如何以紧凑有效的方式索引P N

在其他方面,

  • 定义一个函数p N (a,b),给定一对(a,b)元素I N ,产生一个唯一的P < sub> N 在[0..N(N-1)/ 2-1]
  • 的范围内
  • 定义反向索引函数p N -1 ,给定索引P N ,将产生相应的(a, b)配对

排列P N 的方式不太重要,但是词典顺序可能是最方便的。

示例:

P 4 =((0,1),(0,2),(0,3),(1,2),(1,3),(2, 3))
p 4 (1,3)= 4
p 4 -1 (4)=(1,3)

3 个答案:

答案 0 :(得分:2)

这似乎更像是一个数学问题。

如果我的计算是正确的,那么,

For a pair P (a,b), the number of pairs of type (a,x) [x < b] before P shall be b-a-1.

The number of pairs of type (x,y) [x < a] = (n-1)+(n-2)+(n-3)...+(n-a) = a*n - a(a+1)/2

Hence total number of pairs before P = (b-a-1) + a*n - a(a+1)/2.

因此指数P =(b-a-1)+ a * n - a(a + 1)/ 2。

对于反向索引,首先找到a,因为我们知道对于第一个n-1项,a = 0,对于下一个n-2项,a = 1,等等。

这可以在O(N)时间内迭代这些值并查看它何时超过索引。

一旦找到a,就可以从上面的等式中找到b。

答案 1 :(得分:2)

到目前为止我在这里看到的两个答案都是第一次计算正常,但是反向计算需要循环,这是不必要的。

使用n=5考虑以下示例,显示元素的编号方式。

    0   1   2   3   4
  +---+---+---+---+---+
0 |   |   |   |   |   |
  +---+---+---+---+---+
1 | 0 |   |   |   |   |
  +---+---+---+---+---+
2 | 1 | 4 |   |   |   |
  +---+---+---+---+---+
3 | 2 | 5 | 7 |   |   |
  +---+---+---+---+---+
4 | 3 | 6 | 8 | 9 |   |
  +---+---+---+---+---+

给定元组(x, y)(假设x < y),列x中的第一个索引由

给出
n-1 + n-2 + ... + n-x = (n-1 + n-x) * x / 2 = (2n - x - 1) * x / 2

该列中的偏移量只是y - x - 1。这产生了总表达式

p_n(x, y) = (2n - x - 1) * x / 2 + y-x-1 = (2n - x - 3) * x / 2 + y-1

现在,走另一条路是很棘手的。我们有一些值pn,需要找到xy。通过假设我们正在寻找列中的第一个单元格,即y = x+1,我们可以使我们的生活更简单。如果我们在上面的公式中插入它,我们获得

p = (2n - x - 1) * x / 2

重写此公式会产生

x^2 - (2n-1) * x + 2p = 0

这是一个简单的二次方程,可以求解x:

x = [(2n-1) - Sqrt((2n-1)^2 - 8p)] / 2

当然,我们可能会高估x,因为我们假设y的值尽可能低。但是,我们并没有那么遥远(仍在右栏中),因此对该值进行四舍五入足以得到真实的x

将我们找到的x值插入到原始公式中会为y生成一个非常简单的等式:

x = Floor( [(2n-1) - Sqrt((2n-1)^2 - 8p)] / 2 )
y = p - (2n - x - 3) * x / 2 + 1

可以说,取一个数的平方根是一个缓慢的操作(这是正确的),但这种方法将胜过更大值n的循环。

答案 2 :(得分:0)

索引计算

让a和b为I N 的两个元素,其中&lt; B'/强>

如果我们将P表示为半填充矩阵,那么我们的想法是在每行的开头添加一个偏移量,以便在下一行的开头获得连续的数字。

第0行以0的偏移量开始,包含N-1个值 第1行从N-1开始并包含N-2值
等。

a的偏移值将是(1..a)中i的N-i的总和。

最终对索引将为offset(a)+b

偏移量(a)的计算是通过使用给出前n个整数之和的公式来完成的:s(n)= n(n-1)/ 2.

这里offset(a)将是= s(N)-s(a)。

经过一些数学运算后,得到的公式可以写成:

p N (a,b)= a(2N-a-3)/ 2 + b - 1

P的伪代码是:

function p (a,b)
{
    if (a>b) swap(a,b)
    return a * (2 * N - a - 3) / 2 + b - 1
}

反向索引

所有功劳都归功于Heuster寻找问题的优雅解决方案 有关详细信息,请参阅所选答案。

这是伪代码:

const N1 = 2 * N - 1
const N2 = N1 * N1
function reverse_p (p)
{
    a = floor( (N1 - sqrt(N2 - 8 * p)) / 2)
    b = p - (2 * N - a - 3) * a / 2 + 1
    return (a, b)
}