在排序之前和之后使用重复元素索引数组

时间:2012-07-25 18:41:37

标签: ruby algorithm

这是基本问题:我有一个可能重复元素的整数数组。我需要知道每个元素的索引,但是当我对数组进行排序时,每当我从新数组中选择一个元素时,我希望能够从原始数组中引用相同的元素。

我正在寻找问题的解决方案,或者可能是我正在采取的方法的解决方案。

这是一个数组

a = [1, 2, 3, 4, 3, 5, 2]

有两个2和两个3,但如果我正在使用第一个2(从左侧),我想使用索引1,如果我正在使用第二个{{ 1}},我想使用索引6.所以我使用一个帮助器数组来允许我这样做:

2

我将迭代并用来访问helper = [0, 1, 2, 3, 4, 5, 6] 中的每个元素 我可以使用a完成此操作,但问题在我对数组进行排序时开始。

现在我有一个排序顺序

each_with_index

我使用sort_order = [2, 4, 1, 5, 3] 根据sort_order对sort_by进行排序,以生成

a

您可以假设输入中的所有元素都存在于sorted_a = [2, 2, 4, 1, 5, 3, 3] 中,以避免sort_order例外。

现在的问题是我的sort_by数组应该更新以匹配新的位置。每个元素的排序方式应与排除helper的方式相同,因为不清楚新数组中的前2个是在索引1还是在原始数组的索引6处。

所以我的新助手数组可能看起来像

a

因此,如果我采用这种方法,在给定原始数组和排序顺序的情况下,如何生成new_helper = [1, 6, 3, 0, 5, 2, 4] 数组?

也许有更好的方法可以做到这一点?

5 个答案:

答案 0 :(得分:1)

我建议首先使用辅助数组压缩原始数组,根据来自原始数组的组件对压缩数组进行排序,然后解压缩它们(不幸的是,这种方法不存在,但你可以进行转置)。或者你可以按照Hunter的指示实现你自己的排序逻辑。

答案 1 :(得分:0)

当您在主阵列中交换时,需要交换辅助数组中的值。

loop do
   swapped = false
   0.upto(list.size-2) do |i|
      if list[i] > list[i+1]
         list[i], list[i+1] = list[i+1], list[i] # swap values
         helper[i], helper[i+1] = helper[i+1], helper[i]; #swap helper values
         swapped = true
      end
   end
   break unless swapped
end

示例

irb(main):001:0> def parallel_sort(list, helper)
irb(main):002:1> loop do
irb(main):003:2*    swapped = false
irb(main):004:2>    0.upto(list.size-2) do |i|
irb(main):005:3*       if list[i] > list[i+1]
irb(main):006:4>          list[i], list[i+1] = list[i+1], list[i] # swap values
irb(main):007:4>          helper[i], helper[i+1] = helper[i+1], helper[i]; #swap helper values
irb(main):008:4*          swapped = true
irb(main):009:4>       end
irb(main):010:3>    end
irb(main):011:2>    break unless swapped
irb(main):012:2> end
irb(main):013:1> return [list, helper]
irb(main):014:1> end
=> nil
irb(main):015:0> a = [3,2,1]
=> [3, 2, 1]
irb(main):016:0> b = ["three","two","one"]
=> ["three", "two", "one"]
irb(main):017:0> parallel_sort(a,b)
=> [[1, 2, 3], ["one", "two", "three"]]
irb(main):018:0>

答案 2 :(得分:0)

在循环内进行排序很少是一个好主意....如果你这样做,你可能会更好地使用treap(平均快速但很少操作需要一段时间)或红黑树(相对较差)慢,但给出相当一致的操作时间)。这些非常类似于哈希表,除了它们不那么快,并且它们使用树保持元素按顺序存储。

无论哪种方式,为什么不使用保存值排序依据的类和辅助值?然后他们总是在一起,你不需要自定义排序算法。

答案 3 :(得分:0)

列出原始数据和数据索引的对。像这样:

a = [(1, 0), (2, 1), (3, 2), (4, 3), (3, 4), (5, 5), (2,6)]

对该列表进行排序(按字典顺序排列,或者只是忽略该对的第二部分除了随身携带)。每对中的第二项都会告诉您元素在原始数组中的位置。

答案 4 :(得分:0)

由于你有sort_order,你的数组已经排序了,所以我们应该利用这个事实作为优势。我提出了这个简单的解决方案:

a = [1, 2, 3, 4, 3, 5, 2]
sort_order = [2, 4, 1, 5, 3]

# Save indices
indices = Hash.new { |hash, key| hash[key] = [] }
a.each_with_index { |elem, index| indices[elem] << index }

# Sort the array by placing elements into "right" positions
sorted = []
helper = []
sort_order.each do |elem|
  indices[elem].each do |index|
    sorted << elem
    helper << index
  end
end

p sorted
p helper

该算法基于Counting sort的思想,我稍微修改它以保存索引。