映射排序索引

时间:2012-11-21 12:05:51

标签: algorithm sorting

作为更大算法的一部分,我遇到并解决了这个问题,但我的解决方案似乎不够优雅,我会很感激任何见解。

我有一对可以在笛卡尔平面上被视为点的对列表。我需要生成三个列表:排序的x值,排序的y值,以及一个列表,该列表将排序的x值中的索引与排序的y值中的索引相对应,y值对应于最初配对的y值。 / p>

一个具体的例子可能有助于解释。鉴于以下列表:

((3,7),(15,4),(7,11),(5,0),(4,7),(9,12))

x值的排序列表将是(3,4,5,7,9,15),y值的排序列表将是(0,4,7,7,11,12)。

假设基于零的索引方案,将x列表索引映射到其配对y列表索引的索引的列表将是(2,3,0,4,5,1)。

例如,值7在x列表中显示为索引3。索引3处的映射列表中的值为4,y列表中索引4处的值为11,对应于原始配对(7,11)。

生成此映射列表的最简单方法是什么?

4 个答案:

答案 0 :(得分:3)

这是一个简单的O(nlog n)方法:

  1. 按x对值排序:((3,7),(4,7),(5,0),(7,11),(9,12),(15,4))
  2. 生成一个对列表,其中第一个组件是前一个列表中相同位置的y值,第二个组件从0开始增加:((7,0),(7,1),(0,2) ,(11,3),(12,4),(4,5))
  3. 按其第一个成分(y值)对此列表进行排序:((0,2),(4,5),(7,0),(7,1),(11,3),(12,4) ))
  4. 仔细检查此列表。对于第i个这样的对(y,k),设置yFor [k] = i。 yFor []是你的排序x列表中的列表(井,数组)映射到排序y列表中的索引。
  5. 只需从步骤1中生成的列表中删除第二个元素,即可创建排序的x列表。
  6. 通过对步骤3中生成的列表执行相同的操作来创建已排序的y列表。

答案 1 :(得分:1)

我提出以下建议。 生成未排序的x和y列表。

xs = [3, 15,  7, 5, 4, 9 ]
ys = [7,  4, 11, 0, 7, 12]

将每个元素转换为元组 - 该对中的第一个是坐标,第二个是原始索引。

xs = [(3, 0), (15, 1), ( 7, 2), (5, 3), (4, 4), ( 9, 5)]
ys = [(7, 0), ( 4, 1), (11, 2), (0, 3), (7, 4), (12, 5)]

对两个列表进行排序。

xs = [(3, 0), (4, 4), (5, 3), (7, 2), ( 9, 5), (15, 1)]
ys = [(0, 3), (4, 1), (7, 0), (7, 4), (11, 2), (12, 5)]

创建一个数组y_positions。数组的第n个元素包含最初位于索引n的y元素的当前索引。

创建一个空的index_list。 对于xs的每个元素,获取original_index,第二对元组。 使用y_positions检索具有给定original_index的y元素的当前索引。将当前索引添加到index_list

最后,从xsys中删除索引值。

以下是Python实现示例。

points = ((3, 7), (15, 4), (7, 11), (5, 0), (4, 7), (9, 12))

#generate unsorted lists
xs, ys = zip(*points)

#pair each element with its index
xs = zip(xs, range(len(xs)))
ys = zip(ys, range(len(xs)))

#sort
xs.sort()
ys.sort()

#generate the y positions list.
y_positions = [None] * len(ys)
for i in range(len(ys)):
    original_index = ys[i][1]
    y_positions[original_index] = i

#generate `index_list`
index_list = []
for x, original_index in xs:
    index_list.append(y_positions[original_index])

#remove tuples from x and y lists
xs = zip(*xs)[0]
ys = zip(*ys)[0]

print "xs:", xs
print "ys:", ys
print "index list:", index_list

输出:

xs: (3, 4, 5, 7, 9, 15)
ys: (0, 4, 7, 7, 11, 12)
index list: [2, 3, 0, 4, 5, 1]

y_positionsindex_list的生成是O(n)时间,因此整个算法的复杂性由排序步骤决定。

答案 2 :(得分:1)

感谢您的回答。对于它的价值,我所拥有的解决方案与概述的解决方案非常类似,但正如j_random_hacker指出的那样,不需要地图。让我感到震惊的是,这个小问题看起来比初看​​起来更复杂,我想知道我是否遗漏了一些明显的东西。我已经将我的解决方案重新用于Python进行比较。

points = ((3, 7), (15, 4), (7, 11), (5, 0), (4, 7), (9, 12))

N = len(points)

# Separate the points into their x and y components, tag the values with
# their index into the points list.

# Sort both resulting (value, tag) lists and then unzip them into lists of
# sorted x and y values and the tag information.

xs, s = zip(*sorted(zip([x for (x, y) in points], range(N))))
ys, r = zip(*sorted(zip([y for (x, y) in points], range(N))))

# Generate the mapping list.

t = N * [0]

for i in range(N):
    t[r[i]] = i

index_list = [t[j] for j in s]

print "xs:", xs
print "ys:", ys
print "index_list:", index_list

输出:

xs: (3, 4, 5, 7, 9, 15)
ys: (0, 4, 7, 7, 11, 12)
index_list: [2, 3, 0, 4, 5, 1]

答案 3 :(得分:1)

我刚才通过最初对x中的点进行排序来理解j_random_hacker的意义。这样可以很好地整理东西。感谢。

points = ((3, 7), (15, 4), (7, 11), (5, 0), (4, 7), (9, 12))

N = len(points)

ordered_by_x = sorted(points)
ordered_by_y = sorted(zip([y for (x, y) in ordered_by_x], range(N)))

index_list = N * [0]

for i, (y, k) in enumerate(ordered_by_y):
    index_list[k] = i

xs = [x for (x, y) in ordered_by_x]
ys = [y for (y, k) in ordered_by_y]

print "xs:", xs
print "ys:", ys
print "index_list:", index_list